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