1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/modules/webgl/webgl2_compute_rendering_context_base.h"
6
7 #include <algorithm>
8 #include <memory>
9
10 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
11 #include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
12 #include "third_party/blink/renderer/modules/webgl/webgl_program.h"
13 #include "third_party/blink/renderer/modules/webgl/webgl_uniform_location.h"
14 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h"
15 #include "third_party/blink/renderer/platform/heap/heap.h"
16 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
17
18 namespace blink {
19
WebGL2ComputeRenderingContextBase(CanvasRenderingContextHost * host,std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing,const CanvasContextCreationAttributesCore & requested_attributes)20 WebGL2ComputeRenderingContextBase::WebGL2ComputeRenderingContextBase(
21 CanvasRenderingContextHost* host,
22 std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
23 bool using_gpu_compositing,
24 const CanvasContextCreationAttributesCore& requested_attributes)
25 : WebGL2RenderingContextBase(host,
26 std::move(context_provider),
27 using_gpu_compositing,
28 requested_attributes,
29 Platform::kWebGL2ComputeContextType) {}
30
DestroyContext()31 void WebGL2ComputeRenderingContextBase::DestroyContext() {
32 WebGL2RenderingContextBase::DestroyContext();
33 }
34
InitializeNewContext()35 void WebGL2ComputeRenderingContextBase::InitializeNewContext() {
36 DCHECK(!isContextLost());
37 DCHECK(GetDrawingBuffer());
38
39 bound_dispatch_indirect_buffer_ = nullptr;
40 bound_draw_indirect_buffer_ = nullptr;
41 bound_atomic_counter_buffer_ = nullptr;
42 bound_shader_storage_buffer_ = nullptr;
43
44 GLint max_atomic_counter_buffer_bindings = 0;
45 ContextGL()->GetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
46 &max_atomic_counter_buffer_bindings);
47 bound_indexed_atomic_counter_buffers_.clear();
48 bound_indexed_atomic_counter_buffers_.resize(
49 max_atomic_counter_buffer_bindings);
50
51 GLint max_shader_storage_buffer_bindings = 0;
52 ContextGL()->GetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
53 &max_shader_storage_buffer_bindings);
54 bound_indexed_shader_storage_buffers_.clear();
55 bound_indexed_shader_storage_buffers_.resize(
56 max_shader_storage_buffer_bindings);
57
58 WebGL2RenderingContextBase::InitializeNewContext();
59 }
60
dispatchCompute(GLuint numGroupsX,GLuint numGroupsY,GLuint numGroupsZ)61 void WebGL2ComputeRenderingContextBase::dispatchCompute(GLuint numGroupsX,
62 GLuint numGroupsY,
63 GLuint numGroupsZ) {
64 ContextGL()->DispatchCompute(numGroupsX, numGroupsY, numGroupsZ);
65 }
66
dispatchComputeIndirect(int64_t offset)67 void WebGL2ComputeRenderingContextBase::dispatchComputeIndirect(
68 int64_t offset) {
69 if (!ValidateValueFitNonNegInt32("dispatchComputeIndirect", "offset", offset))
70 return;
71 ContextGL()->DispatchComputeIndirect(static_cast<GLintptr>(offset));
72 }
73
drawArraysIndirect(GLenum mode,int64_t offset)74 void WebGL2ComputeRenderingContextBase::drawArraysIndirect(
75 GLenum mode,
76 int64_t offset) {
77 if (!ValidateValueFitNonNegInt32("drawArraysIndirect", "offset", offset))
78 return;
79
80 if (!ValidateDrawArrays("drawArraysIndirect"))
81 return;
82
83 if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
84 SynthesizeGLError(GL_INVALID_OPERATION, "drawArraysIndirect",
85 "no buffer is bound to enabled attribute");
86 return;
87 }
88
89 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
90 drawing_buffer_.get());
91 OnBeforeDrawCall();
92 ContextGL()->DrawArraysIndirect(
93 mode, reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
94 }
95
drawElementsIndirect(GLenum mode,GLenum type,int64_t offset)96 void WebGL2ComputeRenderingContextBase::drawElementsIndirect(
97 GLenum mode,
98 GLenum type,
99 int64_t offset) {
100 if (!ValidateValueFitNonNegInt32("drawElementsIndirect", "offset", offset))
101 return;
102
103 // The buffer currently bound to the (GL_)DRAW_INDIRECT_BUFFER binding might
104 // be unpopulated at this point, so the validation of element array buffer
105 // offset in it needs to be deferred. By feeding a dummy in-range offset value
106 // here, other validation logic for indexed drawing can be reused.
107 int64_t dummy_offset = 0;
108 if (!ValidateDrawElements("drawElementsIndirect", type, dummy_offset))
109 return;
110
111 if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
112 SynthesizeGLError(GL_INVALID_OPERATION, "drawElementsIndirect",
113 "no buffer is bound to enabled attribute");
114 return;
115 }
116
117 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
118 drawing_buffer_.get());
119 OnBeforeDrawCall();
120 ContextGL()->DrawElementsIndirect(
121 mode, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
122 }
123
getProgramInterfaceParameter(ScriptState * script_state,WebGLProgram * program,GLenum program_interface,GLenum pname)124 ScriptValue WebGL2ComputeRenderingContextBase::getProgramInterfaceParameter(
125 ScriptState* script_state,
126 WebGLProgram* program,
127 GLenum program_interface,
128 GLenum pname) {
129 if (!ValidateWebGLProgramOrShader("getProgramInterfaceParameter", program))
130 return ScriptValue::CreateNull(script_state->GetIsolate());
131 if (!ValidateProgramInterface(
132 "getProgramInterfaceParameter", program_interface))
133 return ScriptValue::CreateNull(script_state->GetIsolate());
134 if (program_interface == GL_ATOMIC_COUNTER_BUFFER &&
135 pname == GL_MAX_NAME_LENGTH) {
136 SynthesizeGLError(GL_INVALID_OPERATION, "getProgramInterfaceParameter",
137 "atomic counter resources are not assigned name strings");
138 return ScriptValue::CreateNull(script_state->GetIsolate());
139 }
140 if (program_interface != GL_ATOMIC_COUNTER_BUFFER &&
141 program_interface != GL_SHADER_STORAGE_BLOCK &&
142 program_interface != GL_UNIFORM_BLOCK &&
143 pname == GL_MAX_NUM_ACTIVE_VARIABLES) {
144 SynthesizeGLError(
145 GL_INVALID_OPERATION, "getProgramInterfaceParameter",
146 "invalid parameter name for the specified program interface");
147 return ScriptValue::CreateNull(script_state->GetIsolate());
148 }
149
150 switch (pname) {
151 case GL_ACTIVE_RESOURCES:
152 case GL_MAX_NAME_LENGTH:
153 case GL_MAX_NUM_ACTIVE_VARIABLES: {
154 GLint value = 0;
155 ContextGL()->GetProgramInterfaceiv(
156 ObjectOrZero(program), program_interface, pname, &value);
157 return WebGLAny(script_state, value);
158 }
159 default:
160 SynthesizeGLError(GL_INVALID_ENUM, "getProgramInterfaceParameter",
161 "invalid parameter name");
162 return ScriptValue::CreateNull(script_state->GetIsolate());
163 }
164 }
165
getProgramResourceIndex(WebGLProgram * program,GLenum program_interface,const String & name)166 GLuint WebGL2ComputeRenderingContextBase::getProgramResourceIndex(
167 WebGLProgram* program,
168 GLenum program_interface,
169 const String& name) {
170 if (!ValidateWebGLProgramOrShader("getProgramResourceIndex", program))
171 return GL_INVALID_INDEX;
172 if (!ValidateProgramInterface("getProgramResourceIndex", program_interface))
173 return GL_INVALID_INDEX;
174 if (program_interface == GL_ATOMIC_COUNTER_BUFFER) {
175 SynthesizeGLError(GL_INVALID_ENUM, "getProgramResourceIndex",
176 "atomic counter resources are not assigned name strings");
177 return GL_INVALID_INDEX;
178 }
179 if (!ValidateString("getProgramResourceIndex", name))
180 return GL_INVALID_INDEX;
181
182 return ContextGL()->GetProgramResourceIndex(
183 ObjectOrZero(program), program_interface, name.Utf8().c_str());
184 }
185
getProgramResourceName(WebGLProgram * program,GLenum program_interface,GLuint index)186 String WebGL2ComputeRenderingContextBase::getProgramResourceName(
187 WebGLProgram* program,
188 GLenum program_interface,
189 GLuint index) {
190 if (!ValidateWebGLProgramOrShader("getProgramResourceName", program))
191 return String();
192 if (!ValidateProgramInterface("getProgramResourceName", program_interface))
193 return String();
194 if (program_interface == GL_ATOMIC_COUNTER_BUFFER) {
195 SynthesizeGLError(GL_INVALID_ENUM, "getProgramResourceName",
196 "atomic counter resources are not assigned name strings");
197 return String();
198 }
199 if (!ValidateProgramResourceIndex(
200 "getProgramResourceName", program, program_interface, index))
201 return String();
202
203 GLint max_name_length = -1;
204 ContextGL()->GetProgramInterfaceiv(ObjectOrZero(program), program_interface,
205 GL_MAX_NAME_LENGTH, &max_name_length);
206 if (max_name_length <= 0)
207 return String();
208 auto name = std::make_unique<GLchar[]>(max_name_length);
209
210 GLsizei length = 0;
211 ContextGL()->GetProgramResourceName(ObjectOrZero(program), program_interface,
212 index, max_name_length, &length,
213 name.get());
214 if (length <= 0)
215 return String();
216 return String(name.get(), static_cast<uint32_t>(length));
217 }
218
219 base::Optional<HeapVector<ScriptValue>>
getProgramResource(ScriptState * script_state,WebGLProgram * program,GLenum program_interface,GLuint index,const Vector<GLenum> & props)220 WebGL2ComputeRenderingContextBase::getProgramResource(
221 ScriptState* script_state,
222 WebGLProgram* program,
223 GLenum program_interface,
224 GLuint index,
225 const Vector<GLenum>& props) {
226 if (!ValidateWebGLProgramOrShader("getProgramResource", program))
227 return base::nullopt;
228 if (!ValidateProgramInterface("getProgramResource", program_interface))
229 return base::nullopt;
230 if (props.IsEmpty()) {
231 SynthesizeGLError(GL_INVALID_VALUE, "getProgramResource",
232 "resource prop array is empty");
233 return base::nullopt;
234 }
235 if (!ValidateProgramResourceIndex(
236 "getProgramResource", program, program_interface, index))
237 return base::nullopt;
238
239 // For props with variable-length return values, their lengths will be queried
240 // first with |auxiliary_props|, and |extended_params| will be adequately
241 // sized for the whole result after that.
242
243 Vector<GLenum> auxiliary_props;
244 Vector<GLint> auxiliary_params;
245 Vector<GLenum> extended_props;
246 Vector<GLint> extended_params;
247 if (!ValidateAndExtendProgramResourceProperties(
248 "getProgramResource", program_interface, props, extended_props))
249 return base::nullopt;
250 extended_params.resize(extended_props.size());
251 for (wtf_size_t i = 0; i < extended_props.size() - props.size(); ++i) {
252 auxiliary_props.push_back(extended_props[i]);
253 auxiliary_params.push_back(-1);
254 extended_params.pop_back();
255 }
256
257 if (auxiliary_props.size()) {
258 ContextGL()->GetProgramResourceiv(ObjectOrZero(program), program_interface,
259 index, auxiliary_props.size(),
260 auxiliary_props.data(),
261 auxiliary_params.size(), nullptr,
262 auxiliary_params.data());
263 for (GLint n : auxiliary_params) {
264 extended_params.resize(extended_params.size() + std::max(n, 0));
265 }
266 }
267
268 GLsizei length = 0;
269 ContextGL()->GetProgramResourceiv(ObjectOrZero(program), program_interface,
270 index, extended_props.size(),
271 extended_props.data(),
272 extended_params.size(), &length,
273 extended_params.data());
274 if (length <= 0) {
275 return base::nullopt;
276 }
277 for (wtf_size_t i = 0; i < auxiliary_params.size(); ++i) {
278 // The returned lengths really should not differ from the previous ones.
279 CHECK_EQ(extended_params[i], auxiliary_params[i]);
280 }
281
282 // Interpret the returned values and construct the result array. The type of
283 // each array element is the natural type for the requested property.
284 HeapVector<ScriptValue> result;
285 wtf_size_t auxiliary_param_index = 0;
286 wtf_size_t extended_param_index = auxiliary_params.size();
287 for (GLenum prop : props) {
288 switch (prop) {
289 case GL_IS_ROW_MAJOR:
290 case GL_REFERENCED_BY_COMPUTE_SHADER:
291 case GL_REFERENCED_BY_FRAGMENT_SHADER:
292 case GL_REFERENCED_BY_VERTEX_SHADER: {
293 bool value = extended_params[extended_param_index];
294 result.push_back(WebGLAny(script_state, value));
295 ++extended_param_index;
296 break;
297 }
298 case GL_ARRAY_STRIDE:
299 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
300 case GL_BLOCK_INDEX:
301 case GL_MATRIX_STRIDE:
302 case GL_OFFSET: {
303 int value = extended_params[extended_param_index];
304 result.push_back(WebGLAny(script_state, value));
305 ++extended_param_index;
306 break;
307 }
308 case GL_LOCATION: {
309 int value = extended_params[extended_param_index];
310 result.push_back(
311 WrapLocation(script_state, value, program, program_interface));
312 ++extended_param_index;
313 break;
314 }
315 case GL_ARRAY_SIZE:
316 case GL_BUFFER_BINDING:
317 case GL_BUFFER_DATA_SIZE:
318 case GL_NAME_LENGTH:
319 case GL_NUM_ACTIVE_VARIABLES:
320 case GL_TOP_LEVEL_ARRAY_SIZE:
321 case GL_TOP_LEVEL_ARRAY_STRIDE: {
322 unsigned value = extended_params[extended_param_index];
323 result.push_back(WebGLAny(script_state, value));
324 ++extended_param_index;
325 break;
326 }
327 case GL_TYPE: {
328 GLenum value = extended_params[extended_param_index];
329 result.push_back(WebGLAny(script_state, value));
330 ++extended_param_index;
331 break;
332 }
333 case GL_ACTIVE_VARIABLES: {
334 DOMUint32Array* value = DOMUint32Array::Create(
335 reinterpret_cast<unsigned*>(&extended_params[extended_param_index]),
336 auxiliary_params[auxiliary_param_index]);
337 result.push_back(WebGLAny(script_state, value));
338 extended_param_index += auxiliary_params[auxiliary_param_index];
339 ++auxiliary_param_index;
340 break;
341 }
342 default:
343 NOTREACHED();
344 }
345 }
346
347 return result;
348 }
349
getProgramResourceLocation(ScriptState * script_state,WebGLProgram * program,GLenum program_interface,const String & name)350 ScriptValue WebGL2ComputeRenderingContextBase::getProgramResourceLocation(
351 ScriptState* script_state,
352 WebGLProgram* program,
353 GLenum program_interface,
354 const String& name) {
355 if (!ValidateWebGLProgramOrShader("getProgramResourceLocation", program))
356 return WrapLocation(script_state, -1, program, program_interface);
357 if (!ValidateProgramInterface(
358 "getProgramResourceLocation", program_interface))
359 return WrapLocation(script_state, -1, program, program_interface);
360 if (!ValidateLocationLength("getProgramResourceLocation", name))
361 return WrapLocation(script_state, -1, program, program_interface);
362 if (!ValidateString("getProgramResourceLocation", name))
363 return WrapLocation(script_state, -1, program, program_interface);
364 if (IsPrefixReserved(name))
365 return WrapLocation(script_state, -1, program, program_interface);
366 if (!program->LinkStatus(this)) {
367 SynthesizeGLError(GL_INVALID_OPERATION, "getProgramResourceLocation",
368 "program not linked");
369 return WrapLocation(script_state, -1, program, program_interface);
370 }
371
372 GLint location = ContextGL()->GetProgramResourceLocation(
373 ObjectOrZero(program), program_interface, name.Utf8().c_str());
374 return WrapLocation(script_state, location, program, program_interface);
375 }
376
bindImageTexture(GLuint unit,WebGLTexture * texture,GLint level,GLboolean layered,GLint layer,GLenum access,GLenum format)377 void WebGL2ComputeRenderingContextBase::bindImageTexture(GLuint unit,
378 WebGLTexture* texture,
379 GLint level,
380 GLboolean layered,
381 GLint layer,
382 GLenum access,
383 GLenum format) {
384 ContextGL()->BindImageTexture(unit, ObjectOrZero(texture), level, layered,
385 layer, access, format);
386 }
387
memoryBarrier(GLbitfield barriers)388 void WebGL2ComputeRenderingContextBase::memoryBarrier(GLbitfield barriers) {
389 ContextGL()->MemoryBarrierEXT(barriers);
390 }
391
memoryBarrierByRegion(GLbitfield barriers)392 void WebGL2ComputeRenderingContextBase::memoryBarrierByRegion(
393 GLbitfield barriers) {
394 ContextGL()->MemoryBarrierByRegion(barriers);
395 }
396
getParameter(ScriptState * script_state,GLenum pname)397 ScriptValue WebGL2ComputeRenderingContextBase::getParameter(
398 ScriptState* script_state,
399 GLenum pname) {
400 if (isContextLost())
401 return ScriptValue::CreateNull(script_state->GetIsolate());
402 switch (pname) {
403 case GL_SHADING_LANGUAGE_VERSION: {
404 return WebGLAny(
405 script_state,
406 "WebGL GLSL ES 3.10 (" +
407 String(ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION)) +
408 ")");
409 }
410 case GL_VERSION: {
411 return WebGLAny(script_state,
412 "WebGL 2.0 Compute (" +
413 String(ContextGL()->GetString(GL_VERSION)) + ")");
414 }
415 case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE:
416 case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
417 case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS:
418 case GL_MAX_COMBINED_ATOMIC_COUNTERS:
419 case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS:
420 case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS:
421 case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE:
422 case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS:
423 case GL_MAX_COMPUTE_UNIFORM_COMPONENTS:
424 case GL_MAX_COMPUTE_UNIFORM_BLOCKS:
425 case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS:
426 case GL_MAX_COMPUTE_IMAGE_UNIFORMS:
427 case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
428 case GL_MAX_FRAGMENT_ATOMIC_COUNTERS:
429 case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS:
430 case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS:
431 case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
432 case GL_MAX_VERTEX_ATOMIC_COUNTERS:
433 case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS:
434 return GetIntParameter(script_state, pname);
435 case GL_MAX_SHADER_STORAGE_BLOCK_SIZE:
436 return GetInt64Parameter(script_state, pname);
437 case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
438 return WebGLAny(script_state, bound_dispatch_indirect_buffer_.Get());
439 case GL_DRAW_INDIRECT_BUFFER_BINDING:
440 return WebGLAny(script_state, bound_draw_indirect_buffer_.Get());
441
442 default:
443 return WebGL2RenderingContextBase::getParameter(script_state, pname);
444 }
445 }
446
getIndexedParameter(ScriptState * script_state,GLenum target,GLuint index)447 ScriptValue WebGL2ComputeRenderingContextBase::getIndexedParameter(
448 ScriptState* script_state,
449 GLenum target,
450 GLuint index) {
451 if (isContextLost())
452 return ScriptValue::CreateNull(script_state->GetIsolate());
453
454 switch (target) {
455 case GL_ATOMIC_COUNTER_BUFFER_BINDING:
456 if (index >= bound_indexed_atomic_counter_buffers_.size()) {
457 SynthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter",
458 "index out of range");
459 return ScriptValue::CreateNull(script_state->GetIsolate());
460 }
461 return WebGLAny(script_state,
462 bound_indexed_atomic_counter_buffers_[index].Get());
463 case GL_SHADER_STORAGE_BUFFER_BINDING:
464 if (index >= bound_indexed_shader_storage_buffers_.size()) {
465 SynthesizeGLError(GL_INVALID_VALUE, "getIndexedParameter",
466 "index out of range");
467 return ScriptValue::CreateNull(script_state->GetIsolate());
468 }
469 return WebGLAny(script_state,
470 bound_indexed_shader_storage_buffers_[index].Get());
471 case GL_MAX_COMPUTE_WORK_GROUP_COUNT:
472 case GL_MAX_COMPUTE_WORK_GROUP_SIZE:
473 case GL_ATOMIC_COUNTER_BUFFER_SIZE:
474 case GL_ATOMIC_COUNTER_BUFFER_START:
475 case GL_SHADER_STORAGE_BUFFER_SIZE:
476 case GL_SHADER_STORAGE_BUFFER_START: {
477 GLint64 value = -1;
478 ContextGL()->GetInteger64i_v(target, index, &value);
479 return WebGLAny(script_state, value);
480 }
481 default:
482 return WebGL2RenderingContextBase::getIndexedParameter(
483 script_state, target, index);
484 }
485 }
486
Trace(Visitor * visitor)487 void WebGL2ComputeRenderingContextBase::Trace(Visitor* visitor) {
488 visitor->Trace(bound_dispatch_indirect_buffer_);
489 visitor->Trace(bound_draw_indirect_buffer_);
490 visitor->Trace(bound_atomic_counter_buffer_);
491 visitor->Trace(bound_indexed_atomic_counter_buffers_);
492 visitor->Trace(bound_shader_storage_buffer_);
493 visitor->Trace(bound_indexed_shader_storage_buffers_);
494 WebGL2RenderingContextBase::Trace(visitor);
495 }
496
ValidateProgramInterface(const char * function_name,GLenum program_interface)497 bool WebGL2ComputeRenderingContextBase::ValidateProgramInterface(
498 const char* function_name,
499 GLenum program_interface) {
500 switch (program_interface) {
501 case GL_ATOMIC_COUNTER_BUFFER:
502 case GL_BUFFER_VARIABLE:
503 case GL_PROGRAM_INPUT:
504 case GL_PROGRAM_OUTPUT:
505 case GL_SHADER_STORAGE_BLOCK:
506 case GL_TRANSFORM_FEEDBACK_VARYING:
507 case GL_UNIFORM:
508 case GL_UNIFORM_BLOCK:
509 return true;
510 default:
511 SynthesizeGLError(GL_INVALID_ENUM, function_name,
512 "invalid program interface");
513 return false;
514 }
515 }
516
ValidateProgramResourceIndex(const char * function_name,WebGLProgram * program,GLenum program_interface,GLuint index)517 bool WebGL2ComputeRenderingContextBase::ValidateProgramResourceIndex(
518 const char* function_name,
519 WebGLProgram* program,
520 GLenum program_interface,
521 GLuint index) {
522 DCHECK(program);
523 if (!program->LinkStatus(this)) {
524 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
525 "program not linked");
526 return false;
527 }
528 GLint active_resources = 0;
529 ContextGL()->GetProgramInterfaceiv(ObjectOrZero(program), program_interface,
530 GL_ACTIVE_RESOURCES, &active_resources);
531 if (index >= static_cast<GLuint>(active_resources)) {
532 SynthesizeGLError(GL_INVALID_VALUE, function_name,
533 "invalid program resource index");
534 return false;
535 }
536 return true;
537 }
538
539 bool
ValidateAndExtendProgramResourceProperties(const char * function_name,GLenum program_interface,const Vector<GLenum> & props,Vector<GLenum> & extended_props)540 WebGL2ComputeRenderingContextBase::ValidateAndExtendProgramResourceProperties(
541 const char* function_name,
542 GLenum program_interface,
543 const Vector<GLenum>& props,
544 Vector<GLenum>& extended_props) {
545 Vector<GLenum> auxiliary_props;
546
547 for (GLenum prop : props) {
548 GLenum error = GL_NO_ERROR;
549
550 switch (prop) {
551 // Handle props with fixed-length return values.
552 case GL_BUFFER_BINDING:
553 case GL_NUM_ACTIVE_VARIABLES:
554 if (program_interface != GL_ATOMIC_COUNTER_BUFFER &&
555 program_interface != GL_SHADER_STORAGE_BLOCK &&
556 program_interface != GL_UNIFORM_BLOCK)
557 error = GL_INVALID_OPERATION;
558 break;
559 case GL_ARRAY_SIZE:
560 if (program_interface != GL_BUFFER_VARIABLE &&
561 program_interface != GL_PROGRAM_INPUT &&
562 program_interface != GL_PROGRAM_OUTPUT &&
563 program_interface != GL_TRANSFORM_FEEDBACK_VARYING &&
564 program_interface != GL_UNIFORM)
565 error = GL_INVALID_OPERATION;
566 break;
567 case GL_ARRAY_STRIDE:
568 case GL_BLOCK_INDEX:
569 case GL_IS_ROW_MAJOR:
570 case GL_MATRIX_STRIDE:
571 if (program_interface != GL_BUFFER_VARIABLE &&
572 program_interface != GL_UNIFORM)
573 error = GL_INVALID_OPERATION;
574 break;
575 case GL_ATOMIC_COUNTER_BUFFER_INDEX:
576 if (program_interface != GL_UNIFORM)
577 error = GL_INVALID_OPERATION;
578 break;
579 case GL_BUFFER_DATA_SIZE:
580 if (program_interface != GL_ATOMIC_COUNTER_BUFFER &&
581 program_interface != GL_SHADER_STORAGE_BLOCK &&
582 program_interface != GL_UNIFORM_BLOCK)
583 error = GL_INVALID_OPERATION;
584 break;
585 case GL_LOCATION:
586 if (program_interface != GL_PROGRAM_INPUT &&
587 program_interface != GL_PROGRAM_OUTPUT &&
588 program_interface != GL_UNIFORM)
589 error = GL_INVALID_OPERATION;
590 break;
591 case GL_NAME_LENGTH:
592 if (program_interface == GL_ATOMIC_COUNTER_BUFFER)
593 error = GL_INVALID_OPERATION;
594 break;
595 case GL_OFFSET:
596 if (program_interface != GL_BUFFER_VARIABLE &&
597 program_interface != GL_UNIFORM)
598 error = GL_INVALID_OPERATION;
599 break;
600 case GL_REFERENCED_BY_VERTEX_SHADER:
601 case GL_REFERENCED_BY_FRAGMENT_SHADER:
602 case GL_REFERENCED_BY_COMPUTE_SHADER:
603 if (program_interface != GL_ATOMIC_COUNTER_BUFFER &&
604 program_interface != GL_BUFFER_VARIABLE &&
605 program_interface != GL_PROGRAM_INPUT &&
606 program_interface != GL_PROGRAM_OUTPUT &&
607 program_interface != GL_SHADER_STORAGE_BLOCK &&
608 program_interface != GL_UNIFORM &&
609 program_interface != GL_UNIFORM_BLOCK)
610 error = GL_INVALID_OPERATION;
611 break;
612 case GL_TOP_LEVEL_ARRAY_SIZE:
613 case GL_TOP_LEVEL_ARRAY_STRIDE:
614 if (program_interface != GL_BUFFER_VARIABLE)
615 error = GL_INVALID_OPERATION;
616 break;
617 case GL_TYPE:
618 if (program_interface != GL_BUFFER_VARIABLE &&
619 program_interface != GL_PROGRAM_INPUT &&
620 program_interface != GL_PROGRAM_OUTPUT &&
621 program_interface != GL_TRANSFORM_FEEDBACK_VARYING &&
622 program_interface != GL_UNIFORM)
623 error = GL_INVALID_OPERATION;
624 break;
625
626 // Handle props with variable-length return values.
627 case GL_ACTIVE_VARIABLES:
628 if (program_interface != GL_ATOMIC_COUNTER_BUFFER &&
629 program_interface != GL_SHADER_STORAGE_BLOCK &&
630 program_interface != GL_UNIFORM_BLOCK) {
631 error = GL_INVALID_OPERATION;
632 break;
633 }
634 auxiliary_props.push_back(GL_NUM_ACTIVE_VARIABLES);
635 break;
636
637 default:
638 error = GL_INVALID_ENUM;
639 }
640
641 switch (error) {
642 case GL_NO_ERROR:
643 break;
644 case GL_INVALID_ENUM:
645 SynthesizeGLError(GL_INVALID_ENUM, function_name,
646 "invalid program resource prop");
647 return false;
648 case GL_INVALID_OPERATION:
649 SynthesizeGLError(
650 GL_INVALID_OPERATION, function_name,
651 "invalid resource prop for the specified program interface");
652 return false;
653 default:
654 NOTREACHED();
655 }
656 }
657
658 extended_props = auxiliary_props;
659 extended_props.AppendVector(props);
660 return true;
661 }
662
WrapLocation(ScriptState * script_state,GLint location,WebGLProgram * program,GLenum program_interface)663 ScriptValue WebGL2ComputeRenderingContextBase::WrapLocation(
664 ScriptState* script_state,
665 GLint location,
666 WebGLProgram* program,
667 GLenum program_interface) {
668 switch (program_interface) {
669 case GL_PROGRAM_INPUT:
670 case GL_PROGRAM_OUTPUT: {
671 return WebGLAny(script_state, location);
672 }
673 case GL_UNIFORM: {
674 if (location == -1)
675 return ScriptValue::CreateNull(script_state->GetIsolate());
676 DCHECK_GE(location, 0);
677 WebGLUniformLocation* uniform_location =
678 MakeGarbageCollected<WebGLUniformLocation>(program, location);
679 return ScriptValue(script_state->GetIsolate(),
680 ToV8(uniform_location, script_state));
681 }
682 default: {
683 return WebGLAny(script_state, location);
684 }
685 }
686 }
687
ValidateShaderType(const char * function_name,GLenum shader_type)688 bool WebGL2ComputeRenderingContextBase::ValidateShaderType(
689 const char* function_name,
690 GLenum shader_type) {
691 switch (shader_type) {
692 case GL_COMPUTE_SHADER:
693 return true;
694 default:
695 return WebGL2RenderingContextBase::ValidateShaderType(
696 function_name, shader_type);
697 }
698 }
699
ValidateBufferTarget(const char * function_name,GLenum target)700 bool WebGL2ComputeRenderingContextBase::ValidateBufferTarget(
701 const char* function_name,
702 GLenum target) {
703 switch (target) {
704 case GL_DISPATCH_INDIRECT_BUFFER:
705 case GL_DRAW_INDIRECT_BUFFER:
706 case GL_ATOMIC_COUNTER_BUFFER:
707 case GL_SHADER_STORAGE_BUFFER:
708 return true;
709 default:
710 return WebGL2RenderingContextBase::ValidateBufferTarget(
711 function_name, target);
712 }
713 }
714
ValidateBufferDataTarget(const char * function_name,GLenum target)715 WebGLBuffer* WebGL2ComputeRenderingContextBase::ValidateBufferDataTarget(
716 const char* function_name,
717 GLenum target) {
718 WebGLBuffer* buffer = nullptr;
719 switch (target) {
720 case GL_DISPATCH_INDIRECT_BUFFER:
721 buffer = bound_dispatch_indirect_buffer_.Get();
722 break;
723 case GL_DRAW_INDIRECT_BUFFER:
724 buffer = bound_draw_indirect_buffer_.Get();
725 break;
726 case GL_ATOMIC_COUNTER_BUFFER:
727 buffer = bound_atomic_counter_buffer_.Get();
728 break;
729 case GL_SHADER_STORAGE_BUFFER:
730 buffer = bound_shader_storage_buffer_.Get();
731 break;
732 default:
733 return WebGL2RenderingContextBase::ValidateBufferDataTarget(
734 function_name, target);
735 }
736 if (!buffer) {
737 SynthesizeGLError(GL_INVALID_OPERATION, function_name, "no buffer");
738 return nullptr;
739 }
740 return buffer;
741 }
742
ValidateAndUpdateBufferBindTarget(const char * function_name,GLenum target,WebGLBuffer * buffer)743 bool WebGL2ComputeRenderingContextBase::ValidateAndUpdateBufferBindTarget(
744 const char* function_name,
745 GLenum target,
746 WebGLBuffer* buffer) {
747 if (!ValidateBufferTarget(function_name, target))
748 return false;
749
750 if (buffer &&
751 !ValidateBufferTargetCompatibility(function_name, target, buffer))
752 return false;
753
754 switch (target) {
755 case GL_DISPATCH_INDIRECT_BUFFER:
756 bound_dispatch_indirect_buffer_ = buffer;
757 break;
758 case GL_DRAW_INDIRECT_BUFFER:
759 bound_draw_indirect_buffer_ = buffer;
760 break;
761 case GL_ATOMIC_COUNTER_BUFFER:
762 bound_atomic_counter_buffer_ = buffer;
763 break;
764 case GL_SHADER_STORAGE_BUFFER:
765 bound_shader_storage_buffer_ = buffer;
766 break;
767 default:
768 return WebGL2RenderingContextBase::ValidateAndUpdateBufferBindTarget(
769 function_name, target, buffer);
770 }
771
772 if (buffer && !buffer->GetInitialTarget())
773 buffer->SetInitialTarget(target);
774 return true;
775 }
776
RemoveBoundBuffer(WebGLBuffer * buffer)777 void WebGL2ComputeRenderingContextBase::RemoveBoundBuffer(WebGLBuffer* buffer) {
778 if (bound_dispatch_indirect_buffer_ == buffer)
779 bound_dispatch_indirect_buffer_ = nullptr;
780 if (bound_draw_indirect_buffer_ == buffer)
781 bound_draw_indirect_buffer_ = nullptr;
782 if (bound_atomic_counter_buffer_ == buffer)
783 bound_atomic_counter_buffer_ = nullptr;
784 if (bound_shader_storage_buffer_ == buffer)
785 bound_shader_storage_buffer_ = nullptr;
786
787 WebGL2RenderingContextBase::RemoveBoundBuffer(buffer);
788 }
789
ValidateBufferTargetCompatibility(const char * function_name,GLenum target,WebGLBuffer * buffer)790 bool WebGL2ComputeRenderingContextBase::ValidateBufferTargetCompatibility(
791 const char* function_name,
792 GLenum target,
793 WebGLBuffer* buffer) {
794 DCHECK(buffer);
795
796 switch (buffer->GetInitialTarget()) {
797 case GL_ELEMENT_ARRAY_BUFFER:
798 switch (target) {
799 case GL_DISPATCH_INDIRECT_BUFFER:
800 case GL_DRAW_INDIRECT_BUFFER:
801 case GL_ATOMIC_COUNTER_BUFFER:
802 case GL_SHADER_STORAGE_BUFFER:
803 SynthesizeGLError(
804 GL_INVALID_OPERATION, function_name,
805 "element array buffers can not be bound to a different target");
806
807 return false;
808 default:
809 break;
810 }
811 break;
812 case GL_DISPATCH_INDIRECT_BUFFER:
813 case GL_DRAW_INDIRECT_BUFFER:
814 case GL_ATOMIC_COUNTER_BUFFER:
815 case GL_SHADER_STORAGE_BUFFER:
816 if (target == GL_ELEMENT_ARRAY_BUFFER) {
817 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
818 "buffers bound to non ELEMENT_ARRAY_BUFFER targets "
819 "can not be bound to ELEMENT_ARRAY_BUFFER target");
820 return false;
821 }
822 return true;
823 default:
824 break;
825 }
826
827 return WebGL2RenderingContextBase::ValidateBufferTargetCompatibility(
828 function_name, target, buffer);
829 }
830
ValidateBufferBaseTarget(const char * function_name,GLenum target)831 bool WebGL2ComputeRenderingContextBase::ValidateBufferBaseTarget(
832 const char* function_name,
833 GLenum target) {
834 switch (target) {
835 case GL_ATOMIC_COUNTER_BUFFER:
836 case GL_SHADER_STORAGE_BUFFER:
837 return true;
838 default:
839 return WebGL2RenderingContextBase::ValidateBufferBaseTarget(
840 function_name, target);
841 }
842 }
843
ValidateAndUpdateBufferBindBaseTarget(const char * function_name,GLenum target,GLuint index,WebGLBuffer * buffer)844 bool WebGL2ComputeRenderingContextBase::ValidateAndUpdateBufferBindBaseTarget(
845 const char* function_name,
846 GLenum target,
847 GLuint index,
848 WebGLBuffer* buffer) {
849 if (!ValidateBufferBaseTarget(function_name, target))
850 return false;
851
852 if (buffer &&
853 !ValidateBufferTargetCompatibility(function_name, target, buffer))
854 return false;
855
856 switch (target) {
857 case GL_ATOMIC_COUNTER_BUFFER:
858 if (index >= bound_indexed_atomic_counter_buffers_.size()) {
859 SynthesizeGLError(GL_INVALID_VALUE, function_name,
860 "index out of range");
861 return false;
862 }
863 bound_indexed_atomic_counter_buffers_[index] = buffer;
864 bound_atomic_counter_buffer_ = buffer;
865 break;
866 case GL_SHADER_STORAGE_BUFFER:
867 if (index >= bound_indexed_shader_storage_buffers_.size()) {
868 SynthesizeGLError(GL_INVALID_VALUE, function_name,
869 "index out of range");
870 return false;
871 }
872 bound_indexed_shader_storage_buffers_[index] = buffer;
873 bound_shader_storage_buffer_ = buffer;
874 break;
875 default:
876 return WebGL2RenderingContextBase::ValidateAndUpdateBufferBindBaseTarget(
877 function_name, target, index, buffer);
878 }
879
880 if (buffer && !buffer->GetInitialTarget())
881 buffer->SetInitialTarget(target);
882 return true;
883 }
884
885 } // namespace blink
886