1 /*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
27
28 #include <memory>
29 #include <utility>
30
31 #include "base/feature_list.h"
32 #include "base/numerics/checked_math.h"
33 #include "base/stl_util.h"
34 #include "build/build_config.h"
35 #include "gpu/GLES2/gl2extchromium.h"
36 #include "gpu/command_buffer/client/gles2_interface.h"
37 #include "gpu/command_buffer/common/capabilities.h"
38 #include "gpu/config/gpu_feature_info.h"
39 #include "third_party/blink/public/common/features.h"
40 #include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
41 #include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
42 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
43 #include "third_party/blink/public/mojom/gpu/gpu.mojom-blink.h"
44 #include "third_party/blink/public/platform/platform.h"
45 #include "third_party/blink/public/platform/task_type.h"
46 #include "third_party/blink/renderer/bindings/modules/v8/html_canvas_element_or_offscreen_canvas.h"
47 #include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
48 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
49 #include "third_party/blink/renderer/core/frame/dactyloscoper.h"
50 #include "third_party/blink/renderer/core/frame/local_frame.h"
51 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
52 #include "third_party/blink/renderer/core/frame/settings.h"
53 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h"
54 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
55 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
56 #include "third_party/blink/renderer/core/html/html_image_element.h"
57 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
58 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
59 #include "third_party/blink/renderer/core/inspector/console_message.h"
60 #include "third_party/blink/renderer/core/layout/layout_box.h"
61 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
62 #include "third_party/blink/renderer/core/probe/core_probes.h"
63 #include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
64 #include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
65 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
66 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
67 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
68 #include "third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h"
69 #include "third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h"
70 #include "third_party/blink/renderer/modules/webgl/ext_blend_min_max.h"
71 #include "third_party/blink/renderer/modules/webgl/ext_frag_depth.h"
72 #include "third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.h"
73 #include "third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.h"
74 #include "third_party/blink/renderer/modules/webgl/gl_string_query.h"
75 #include "third_party/blink/renderer/modules/webgl/oes_element_index_uint.h"
76 #include "third_party/blink/renderer/modules/webgl/oes_standard_derivatives.h"
77 #include "third_party/blink/renderer/modules/webgl/oes_texture_float.h"
78 #include "third_party/blink/renderer/modules/webgl/oes_texture_float_linear.h"
79 #include "third_party/blink/renderer/modules/webgl/oes_texture_half_float.h"
80 #include "third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.h"
81 #include "third_party/blink/renderer/modules/webgl/oes_vertex_array_object.h"
82 #include "third_party/blink/renderer/modules/webgl/webgl_active_info.h"
83 #include "third_party/blink/renderer/modules/webgl/webgl_buffer.h"
84 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.h"
85 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.h"
86 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.h"
87 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.h"
88 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.h"
89 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.h"
90 #include "third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h"
91 #include "third_party/blink/renderer/modules/webgl/webgl_context_event.h"
92 #include "third_party/blink/renderer/modules/webgl/webgl_context_group.h"
93 #include "third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.h"
94 #include "third_party/blink/renderer/modules/webgl/webgl_debug_shaders.h"
95 #include "third_party/blink/renderer/modules/webgl/webgl_depth_texture.h"
96 #include "third_party/blink/renderer/modules/webgl/webgl_draw_buffers.h"
97 #include "third_party/blink/renderer/modules/webgl/webgl_framebuffer.h"
98 #include "third_party/blink/renderer/modules/webgl/webgl_lose_context.h"
99 #include "third_party/blink/renderer/modules/webgl/webgl_program.h"
100 #include "third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h"
101 #include "third_party/blink/renderer/modules/webgl/webgl_shader.h"
102 #include "third_party/blink/renderer/modules/webgl/webgl_shader_precision_format.h"
103 #include "third_party/blink/renderer/modules/webgl/webgl_uniform_location.h"
104 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h"
105 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h"
106 #include "third_party/blink/renderer/modules/webgl/webgl_video_texture.h"
107 #include "third_party/blink/renderer/modules/webgl/webgl_video_texture_enum.h"
108 #include "third_party/blink/renderer/modules/xr/xr_system.h"
109 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
110 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
111 #include "third_party/blink/renderer/platform/geometry/int_size.h"
112 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
113 #include "third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h"
114 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
115 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
116 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
117 #include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h"
118 #include "third_party/blink/renderer/platform/heap/heap.h"
119 #include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
120 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
121 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
122 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
123 #include "third_party/blink/renderer/platform/wtf/functional.h"
124 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
125 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
126 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
127
128 namespace blink {
129
130 bool WebGLRenderingContextBase::webgl_context_limits_initialized_ = false;
131 unsigned WebGLRenderingContextBase::max_active_webgl_contexts_ = 0;
132 unsigned WebGLRenderingContextBase::max_active_webgl_contexts_on_worker_ = 0;
133
134 namespace {
135
136 constexpr base::TimeDelta kDurationBetweenRestoreAttempts =
137 base::TimeDelta::FromSeconds(1);
138 const int kMaxGLErrorsAllowedToConsole = 256;
139
WebGLContextLimitMutex()140 Mutex& WebGLContextLimitMutex() {
141 DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, ());
142 return mutex;
143 }
144
145 using WebGLRenderingContextBaseSet =
146 HeapHashSet<WeakMember<WebGLRenderingContextBase>>;
ActiveContexts()147 WebGLRenderingContextBaseSet& ActiveContexts() {
148 DEFINE_THREAD_SAFE_STATIC_LOCAL(
149 ThreadSpecific<Persistent<WebGLRenderingContextBaseSet>>, active_contexts,
150 ());
151 Persistent<WebGLRenderingContextBaseSet>& active_contexts_persistent =
152 *active_contexts;
153 if (!active_contexts_persistent) {
154 active_contexts_persistent =
155 MakeGarbageCollected<WebGLRenderingContextBaseSet>();
156 active_contexts_persistent.RegisterAsStaticReference();
157 }
158 return *active_contexts_persistent;
159 }
160
161 using WebGLRenderingContextBaseMap =
162 HeapHashMap<WeakMember<WebGLRenderingContextBase>, int>;
ForciblyEvictedContexts()163 WebGLRenderingContextBaseMap& ForciblyEvictedContexts() {
164 DEFINE_THREAD_SAFE_STATIC_LOCAL(
165 ThreadSpecific<Persistent<WebGLRenderingContextBaseMap>>,
166 forcibly_evicted_contexts, ());
167 Persistent<WebGLRenderingContextBaseMap>&
168 forcibly_evicted_contexts_persistent = *forcibly_evicted_contexts;
169 if (!forcibly_evicted_contexts_persistent) {
170 forcibly_evicted_contexts_persistent =
171 MakeGarbageCollected<WebGLRenderingContextBaseMap>();
172 forcibly_evicted_contexts_persistent.RegisterAsStaticReference();
173 }
174 return *forcibly_evicted_contexts_persistent;
175 }
176
177 } // namespace
178
ScopedRGBEmulationColorMask(WebGLRenderingContextBase * context,GLboolean * color_mask,DrawingBuffer * drawing_buffer)179 ScopedRGBEmulationColorMask::ScopedRGBEmulationColorMask(
180 WebGLRenderingContextBase* context,
181 GLboolean* color_mask,
182 DrawingBuffer* drawing_buffer)
183 : context_(context),
184 requires_emulation_(drawing_buffer->RequiresAlphaChannelToBePreserved()) {
185 if (requires_emulation_) {
186 context_->active_scoped_rgb_emulation_color_masks_++;
187 memcpy(color_mask_, color_mask, 4 * sizeof(GLboolean));
188 context_->ContextGL()->ColorMask(color_mask_[0], color_mask_[1],
189 color_mask_[2], false);
190 }
191 }
192
~ScopedRGBEmulationColorMask()193 ScopedRGBEmulationColorMask::~ScopedRGBEmulationColorMask() {
194 if (requires_emulation_) {
195 DCHECK(context_->active_scoped_rgb_emulation_color_masks_);
196 context_->active_scoped_rgb_emulation_color_masks_--;
197 context_->ContextGL()->ColorMask(color_mask_[0], color_mask_[1],
198 color_mask_[2], color_mask_[3]);
199 }
200 }
201
InitializeWebGLContextLimits(WebGraphicsContext3DProvider * context_provider)202 void WebGLRenderingContextBase::InitializeWebGLContextLimits(
203 WebGraphicsContext3DProvider* context_provider) {
204 MutexLocker locker(WebGLContextLimitMutex());
205 if (!webgl_context_limits_initialized_) {
206 // These do not change over the lifetime of the browser.
207 auto webgl_preferences = context_provider->GetWebglPreferences();
208 max_active_webgl_contexts_ = webgl_preferences.max_active_webgl_contexts;
209 max_active_webgl_contexts_on_worker_ =
210 webgl_preferences.max_active_webgl_contexts_on_worker;
211 webgl_context_limits_initialized_ = true;
212 }
213 }
214
CurrentMaxGLContexts()215 unsigned WebGLRenderingContextBase::CurrentMaxGLContexts() {
216 MutexLocker locker(WebGLContextLimitMutex());
217 DCHECK(webgl_context_limits_initialized_);
218 return IsMainThread() ? max_active_webgl_contexts_
219 : max_active_webgl_contexts_on_worker_;
220 }
221
ForciblyLoseOldestContext(const String & reason)222 void WebGLRenderingContextBase::ForciblyLoseOldestContext(
223 const String& reason) {
224 WebGLRenderingContextBase* candidate = OldestContext();
225 if (!candidate)
226 return;
227
228 candidate->PrintWarningToConsole(reason);
229 probe::DidFireWebGLWarning(candidate->canvas());
230
231 // This will call deactivateContext once the context has actually been lost.
232 candidate->ForceLostContext(WebGLRenderingContextBase::kSyntheticLostContext,
233 WebGLRenderingContextBase::kWhenAvailable);
234 }
235
OldestContext()236 WebGLRenderingContextBase* WebGLRenderingContextBase::OldestContext() {
237 if (ActiveContexts().IsEmpty())
238 return nullptr;
239
240 WebGLRenderingContextBase* candidate = *(ActiveContexts().begin());
241 DCHECK(!candidate->isContextLost());
242 for (WebGLRenderingContextBase* context : ActiveContexts()) {
243 DCHECK(!context->isContextLost());
244 if (context->ContextGL()->GetLastFlushIdCHROMIUM() <
245 candidate->ContextGL()->GetLastFlushIdCHROMIUM()) {
246 candidate = context;
247 }
248 }
249
250 return candidate;
251 }
252
OldestEvictedContext()253 WebGLRenderingContextBase* WebGLRenderingContextBase::OldestEvictedContext() {
254 if (ForciblyEvictedContexts().IsEmpty())
255 return nullptr;
256
257 WebGLRenderingContextBase* candidate = nullptr;
258 int generation = -1;
259 for (WebGLRenderingContextBase* context : ForciblyEvictedContexts().Keys()) {
260 if (!candidate || ForciblyEvictedContexts().at(context) < generation) {
261 candidate = context;
262 generation = ForciblyEvictedContexts().at(context);
263 }
264 }
265
266 return candidate;
267 }
268
ActivateContext(WebGLRenderingContextBase * context)269 void WebGLRenderingContextBase::ActivateContext(
270 WebGLRenderingContextBase* context) {
271 unsigned max_gl_contexts = CurrentMaxGLContexts();
272 unsigned removed_contexts = 0;
273 while (ActiveContexts().size() >= max_gl_contexts &&
274 removed_contexts < max_gl_contexts) {
275 ForciblyLoseOldestContext(
276 "WARNING: Too many active WebGL contexts. Oldest context will be "
277 "lost.");
278 removed_contexts++;
279 }
280
281 DCHECK(!context->isContextLost());
282 ActiveContexts().insert(context);
283 }
284
DeactivateContext(WebGLRenderingContextBase * context)285 void WebGLRenderingContextBase::DeactivateContext(
286 WebGLRenderingContextBase* context) {
287 ActiveContexts().erase(context);
288 }
289
AddToEvictedList(WebGLRenderingContextBase * context)290 void WebGLRenderingContextBase::AddToEvictedList(
291 WebGLRenderingContextBase* context) {
292 static int generation = 0;
293 ForciblyEvictedContexts().Set(context, generation++);
294 }
295
RemoveFromEvictedList(WebGLRenderingContextBase * context)296 void WebGLRenderingContextBase::RemoveFromEvictedList(
297 WebGLRenderingContextBase* context) {
298 ForciblyEvictedContexts().erase(context);
299 }
300
RestoreEvictedContext(WebGLRenderingContextBase * context)301 void WebGLRenderingContextBase::RestoreEvictedContext(
302 WebGLRenderingContextBase* context) {
303 // These two sets keep weak references to their contexts;
304 // verify that the GC already removed the |context| entries.
305 DCHECK(!ForciblyEvictedContexts().Contains(context));
306 DCHECK(!ActiveContexts().Contains(context));
307
308 unsigned max_gl_contexts = CurrentMaxGLContexts();
309 // Try to re-enable the oldest inactive contexts.
310 while (ActiveContexts().size() < max_gl_contexts &&
311 ForciblyEvictedContexts().size()) {
312 WebGLRenderingContextBase* evicted_context = OldestEvictedContext();
313 if (!evicted_context->restore_allowed_) {
314 ForciblyEvictedContexts().erase(evicted_context);
315 continue;
316 }
317
318 IntSize desired_size = DrawingBuffer::AdjustSize(
319 evicted_context->ClampedCanvasSize(), IntSize(),
320 evicted_context->max_texture_size_);
321
322 // If there's room in the pixel budget for this context, restore it.
323 if (!desired_size.IsEmpty()) {
324 ForciblyEvictedContexts().erase(evicted_context);
325 evicted_context->ForceRestoreContext();
326 }
327 break;
328 }
329 }
330
331 namespace {
332
Clamp(GLint value,GLint min,GLint max)333 GLint Clamp(GLint value, GLint min, GLint max) {
334 if (value < min)
335 value = min;
336 if (value > max)
337 value = max;
338 return value;
339 }
340
341 // Strips comments from shader text. This allows non-ASCII characters
342 // to be used in comments without potentially breaking OpenGL
343 // implementations not expecting characters outside the GLSL ES set.
344 class StripComments {
345 public:
StripComments(const String & str)346 StripComments(const String& str)
347 : parse_state_(kBeginningOfLine),
348 source_string_(str),
349 length_(str.length()),
350 position_(0) {
351 Parse();
352 }
353
Result()354 String Result() { return builder_.ToString(); }
355
356 private:
HasMoreCharacters() const357 bool HasMoreCharacters() const { return (position_ < length_); }
358
Parse()359 void Parse() {
360 while (HasMoreCharacters()) {
361 Process(Current());
362 // process() might advance the position.
363 if (HasMoreCharacters())
364 Advance();
365 }
366 }
367
368 void Process(UChar);
369
Peek(UChar & character) const370 bool Peek(UChar& character) const {
371 if (position_ + 1 >= length_)
372 return false;
373 character = source_string_[position_ + 1];
374 return true;
375 }
376
Current()377 UChar Current() {
378 SECURITY_DCHECK(position_ < length_);
379 return source_string_[position_];
380 }
381
Advance()382 void Advance() { ++position_; }
383
IsNewline(UChar character)384 static bool IsNewline(UChar character) {
385 // Don't attempt to canonicalize newline related characters.
386 return (character == '\n' || character == '\r');
387 }
388
Emit(UChar character)389 void Emit(UChar character) { builder_.Append(character); }
390
391 enum ParseState {
392 // Have not seen an ASCII non-whitespace character yet on
393 // this line. Possible that we might see a preprocessor
394 // directive.
395 kBeginningOfLine,
396
397 // Have seen at least one ASCII non-whitespace character
398 // on this line.
399 kMiddleOfLine,
400
401 // Handling a preprocessor directive. Passes through all
402 // characters up to the end of the line. Disables comment
403 // processing.
404 kInPreprocessorDirective,
405
406 // Handling a single-line comment. The comment text is
407 // replaced with a single space.
408 kInSingleLineComment,
409
410 // Handling a multi-line comment. Newlines are passed
411 // through to preserve line numbers.
412 kInMultiLineComment
413 };
414
415 ParseState parse_state_;
416 String source_string_;
417 unsigned length_;
418 unsigned position_;
419 StringBuilder builder_;
420 };
421
Process(UChar c)422 void StripComments::Process(UChar c) {
423 if (IsNewline(c)) {
424 // No matter what state we are in, pass through newlines
425 // so we preserve line numbers.
426 Emit(c);
427
428 if (parse_state_ != kInMultiLineComment)
429 parse_state_ = kBeginningOfLine;
430
431 return;
432 }
433
434 UChar temp = 0;
435 switch (parse_state_) {
436 case kBeginningOfLine:
437 if (WTF::IsASCIISpace(c)) {
438 Emit(c);
439 break;
440 }
441
442 if (c == '#') {
443 parse_state_ = kInPreprocessorDirective;
444 Emit(c);
445 break;
446 }
447
448 // Transition to normal state and re-handle character.
449 parse_state_ = kMiddleOfLine;
450 Process(c);
451 break;
452
453 case kMiddleOfLine:
454 case kInPreprocessorDirective:
455 if (c == '/' && Peek(temp)) {
456 if (temp == '/') {
457 parse_state_ = kInSingleLineComment;
458 Emit(' ');
459 Advance();
460 break;
461 }
462
463 if (temp == '*') {
464 parse_state_ = kInMultiLineComment;
465 // Emit the comment start in case the user has
466 // an unclosed comment and we want to later
467 // signal an error.
468 Emit('/');
469 Emit('*');
470 Advance();
471 break;
472 }
473 }
474
475 Emit(c);
476 break;
477
478 case kInSingleLineComment:
479 // Line-continuation characters are processed before comment processing.
480 // Advance string if a new line character is immediately behind
481 // line-continuation character.
482 if (c == '\\') {
483 if (Peek(temp) && IsNewline(temp))
484 Advance();
485 }
486
487 // The newline code at the top of this function takes care
488 // of resetting our state when we get out of the
489 // single-line comment. Swallow all other characters.
490 break;
491
492 case kInMultiLineComment:
493 if (c == '*' && Peek(temp) && temp == '/') {
494 Emit('*');
495 Emit('/');
496 parse_state_ = kMiddleOfLine;
497 Advance();
498 break;
499 }
500
501 // Swallow all other characters. Unclear whether we may
502 // want or need to just emit a space per character to try
503 // to preserve column numbers for debugging purposes.
504 break;
505 }
506 }
507
508 static bool g_should_fail_context_creation_for_testing = false;
509 } // namespace
510
511 class ScopedTexture2DRestorer {
512 STACK_ALLOCATED();
513
514 public:
ScopedTexture2DRestorer(WebGLRenderingContextBase * context)515 explicit ScopedTexture2DRestorer(WebGLRenderingContextBase* context)
516 : context_(context) {}
517
~ScopedTexture2DRestorer()518 ~ScopedTexture2DRestorer() { context_->RestoreCurrentTexture2D(); }
519
520 private:
521 WebGLRenderingContextBase* context_;
522 };
523
524 class ScopedFramebufferRestorer {
525 STACK_ALLOCATED();
526
527 public:
ScopedFramebufferRestorer(WebGLRenderingContextBase * context)528 explicit ScopedFramebufferRestorer(WebGLRenderingContextBase* context)
529 : context_(context) {}
530
~ScopedFramebufferRestorer()531 ~ScopedFramebufferRestorer() { context_->RestoreCurrentFramebuffer(); }
532
533 private:
534 WebGLRenderingContextBase* context_;
535 };
536
537 class ScopedUnpackParametersResetRestore {
538 STACK_ALLOCATED();
539
540 public:
ScopedUnpackParametersResetRestore(WebGLRenderingContextBase * context,bool enabled=true)541 explicit ScopedUnpackParametersResetRestore(
542 WebGLRenderingContextBase* context,
543 bool enabled = true)
544 : context_(context), enabled_(enabled) {
545 if (enabled)
546 context_->ResetUnpackParameters();
547 }
548
~ScopedUnpackParametersResetRestore()549 ~ScopedUnpackParametersResetRestore() {
550 if (enabled_)
551 context_->RestoreUnpackParameters();
552 }
553
554 private:
555 WebGLRenderingContextBase* context_;
556 bool enabled_;
557 };
558
FormatWebGLStatusString(const StringView & gl_info,const StringView & info_string,StringBuilder & builder)559 static void FormatWebGLStatusString(const StringView& gl_info,
560 const StringView& info_string,
561 StringBuilder& builder) {
562 if (info_string.IsEmpty())
563 return;
564 builder.Append(", ");
565 builder.Append(gl_info);
566 builder.Append(" = ");
567 builder.Append(info_string);
568 }
569
ExtractWebGLContextCreationError(const Platform::GraphicsInfo & info)570 static String ExtractWebGLContextCreationError(
571 const Platform::GraphicsInfo& info) {
572 StringBuilder builder;
573 builder.Append("Could not create a WebGL context");
574 FormatWebGLStatusString(
575 "VENDOR",
576 info.vendor_id ? String::Format("0x%04x", info.vendor_id) : "0xffff",
577 builder);
578 FormatWebGLStatusString(
579 "DEVICE",
580 info.device_id ? String::Format("0x%04x", info.device_id) : "0xffff",
581 builder);
582 FormatWebGLStatusString("GL_VENDOR", info.vendor_info, builder);
583 FormatWebGLStatusString("GL_RENDERER", info.renderer_info, builder);
584 FormatWebGLStatusString("GL_VERSION", info.driver_version, builder);
585 FormatWebGLStatusString("Sandboxed", info.sandboxed ? "yes" : "no", builder);
586 FormatWebGLStatusString("Optimus", info.optimus ? "yes" : "no", builder);
587 FormatWebGLStatusString("AMD switchable", info.amd_switchable ? "yes" : "no",
588 builder);
589 FormatWebGLStatusString(
590 "Reset notification strategy",
591 String::Format("0x%04x", info.reset_notification_strategy).Utf8().c_str(),
592 builder);
593 FormatWebGLStatusString("ErrorMessage", info.error_message.Utf8().c_str(),
594 builder);
595 builder.Append('.');
596 return builder.ToString();
597 }
598
SupportOwnOffscreenSurface(ExecutionContext * execution_context)599 bool WebGLRenderingContextBase::SupportOwnOffscreenSurface(
600 ExecutionContext* execution_context) {
601 // Using an own offscreen surface disables virtualized contexts, and this
602 // doesn't currently work properly, see https://crbug.com/691102.
603 // TODO(https://crbug.com/791755): Remove this function and related code once
604 // the replacement is ready.
605 return false;
606 }
607
608 std::unique_ptr<WebGraphicsContext3DProvider>
CreateContextProviderInternal(CanvasRenderingContextHost * host,const CanvasContextCreationAttributesCore & attributes,Platform::ContextType context_type,bool * using_gpu_compositing)609 WebGLRenderingContextBase::CreateContextProviderInternal(
610 CanvasRenderingContextHost* host,
611 const CanvasContextCreationAttributesCore& attributes,
612 Platform::ContextType context_type,
613 bool* using_gpu_compositing) {
614 DCHECK(host);
615 ExecutionContext* execution_context = host->GetTopExecutionContext();
616 DCHECK(execution_context);
617
618 Platform::ContextAttributes context_attributes = ToPlatformContextAttributes(
619 attributes, context_type, SupportOwnOffscreenSurface(execution_context));
620
621 Platform::GraphicsInfo gl_info;
622 std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
623 const auto& url = execution_context->Url();
624 if (IsMainThread()) {
625 // Ask for gpu compositing mode when making the context. The context will be
626 // lost if the mode changes.
627 *using_gpu_compositing = !Platform::Current()->IsGpuCompositingDisabled();
628 context_provider =
629 Platform::Current()->CreateOffscreenGraphicsContext3DProvider(
630 context_attributes, url, &gl_info);
631 } else {
632 context_provider = CreateContextProviderOnWorkerThread(
633 context_attributes, &gl_info, using_gpu_compositing, url);
634 }
635 if (context_provider && !context_provider->BindToCurrentThread()) {
636 context_provider = nullptr;
637 gl_info.error_message =
638 String("bindToCurrentThread failed: " + String(gl_info.error_message));
639 }
640 if (!context_provider || g_should_fail_context_creation_for_testing) {
641 g_should_fail_context_creation_for_testing = false;
642 host->HostDispatchEvent(
643 WebGLContextEvent::Create(event_type_names::kWebglcontextcreationerror,
644 ExtractWebGLContextCreationError(gl_info)));
645 return nullptr;
646 }
647 gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
648 if (!String(gl->GetString(GL_EXTENSIONS))
649 .Contains("GL_OES_packed_depth_stencil")) {
650 host->HostDispatchEvent(WebGLContextEvent::Create(
651 event_type_names::kWebglcontextcreationerror,
652 "OES_packed_depth_stencil support is required."));
653 return nullptr;
654 }
655 return context_provider;
656 }
657
658 std::unique_ptr<WebGraphicsContext3DProvider>
CreateWebGraphicsContext3DProvider(CanvasRenderingContextHost * host,const CanvasContextCreationAttributesCore & attributes,Platform::ContextType context_type,bool * using_gpu_compositing)659 WebGLRenderingContextBase::CreateWebGraphicsContext3DProvider(
660 CanvasRenderingContextHost* host,
661 const CanvasContextCreationAttributesCore& attributes,
662 Platform::ContextType context_type,
663 bool* using_gpu_compositing) {
664 // The host might block creation of a new WebGL context despite the
665 // page settings; in particular, if WebGL contexts were lost one or
666 // more times via the GL_ARB_robustness extension.
667 if (host->IsWebGLBlocked()) {
668 host->SetContextCreationWasBlocked();
669 host->HostDispatchEvent(WebGLContextEvent::Create(
670 event_type_names::kWebglcontextcreationerror,
671 "Web page caused context loss and was blocked"));
672 return nullptr;
673 }
674 if ((context_type == Platform::kWebGL1ContextType &&
675 !host->IsWebGL1Enabled()) ||
676 (context_type == Platform::kWebGL2ContextType &&
677 !host->IsWebGL2Enabled())) {
678 host->HostDispatchEvent(WebGLContextEvent::Create(
679 event_type_names::kWebglcontextcreationerror,
680 "disabled by enterprise policy or commandline switch"));
681 return nullptr;
682 }
683
684 return CreateContextProviderInternal(host, attributes, context_type,
685 using_gpu_compositing);
686 }
687
ForceNextWebGLContextCreationToFail()688 void WebGLRenderingContextBase::ForceNextWebGLContextCreationToFail() {
689 g_should_fail_context_creation_for_testing = true;
690 }
691
TransferToImageBitmapBase(ScriptState * script_state)692 ImageBitmap* WebGLRenderingContextBase::TransferToImageBitmapBase(
693 ScriptState* script_state) {
694 WebFeature feature = WebFeature::kOffscreenCanvasTransferToImageBitmapWebGL;
695 UseCounter::Count(ExecutionContext::From(script_state), feature);
696 return MakeGarbageCollected<ImageBitmap>(
697 GetDrawingBuffer()->TransferToStaticBitmapImage());
698 }
699
commit()700 void WebGLRenderingContextBase::commit() {
701 if (!GetDrawingBuffer() || (Host() && Host()->IsOffscreenCanvas()))
702 return;
703
704 int width = GetDrawingBuffer()->Size().Width();
705 int height = GetDrawingBuffer()->Size().Height();
706
707 if (PaintRenderingResultsToCanvas(kBackBuffer)) {
708 if (Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU)) {
709 Host()->Commit(Host()->ResourceProvider()->ProduceCanvasResource(),
710 SkIRect::MakeWH(width, height));
711 }
712 }
713 MarkLayerComposited();
714 }
715
GetImage()716 scoped_refptr<StaticBitmapImage> WebGLRenderingContextBase::GetImage() {
717 if (!GetDrawingBuffer())
718 return nullptr;
719
720 ScopedFramebufferRestorer fbo_restorer(this);
721 GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
722 // Use the drawing buffer size here instead of the canvas size to ensure that
723 // sizing is consistent. The forced downsizing logic in Reshape() can lead to
724 // the drawing buffer being smaller than the canvas size.
725 // See https://crbug.com/845742.
726 IntSize size = GetDrawingBuffer()->Size();
727 // Since we are grabbing a snapshot that is not for compositing, we use a
728 // custom resource provider. This avoids consuming compositing-specific
729 // resources (e.g. GpuMemoryBuffer)
730 auto color_params = ColorParams();
731 std::unique_ptr<CanvasResourceProvider> resource_provider =
732 CanvasResourceProvider::CreateSharedImageProvider(
733 size, GetDrawingBuffer()->FilterQuality(), color_params,
734 CanvasResourceProvider::ShouldInitialize::kNo,
735 SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
736 is_origin_top_left_, 0u /*shared_image_usage_flags*/);
737 // todo(bug 1090962) This CPU fallback is needed as it would break
738 // webgl_conformance_gles_passthrough_tests on Android FYI for Nexus 5x.
739 if (!resource_provider || !resource_provider->IsValid()) {
740 resource_provider = CanvasResourceProvider::CreateBitmapProvider(
741 size, GetDrawingBuffer()->FilterQuality(), color_params,
742 CanvasResourceProvider::ShouldInitialize::kNo);
743 }
744
745 if (!resource_provider || !resource_provider->IsValid())
746 return nullptr;
747
748 if (!CopyRenderingResultsFromDrawingBuffer(resource_provider.get(),
749 kBackBuffer)) {
750 // CopyRenderingResultsFromDrawingBuffer will handle both CPU and GPU cases.
751 NOTREACHED();
752 return nullptr;
753 }
754 return resource_provider->Snapshot();
755 }
756
makeXRCompatible(ScriptState * script_state,ExceptionState & exception_state)757 ScriptPromise WebGLRenderingContextBase::makeXRCompatible(
758 ScriptState* script_state,
759 ExceptionState& exception_state) {
760 if (isContextLost()) {
761 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
762 "Context lost.");
763 return ScriptPromise();
764 }
765
766 // Return a resolved promise if we're already xr compatible. Once we're
767 // compatible, we should always be compatible unless a context lost occurs.
768 // DispatchContextLostEvent() resets this flag to false.
769 if (xr_compatible_)
770 return ScriptPromise::CastUndefined(script_state);
771
772 if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled()) {
773 xr_compatible_ = true;
774 return ScriptPromise::CastUndefined(script_state);
775 }
776
777 // If there's a request currently in progress, return the same promise.
778 if (make_xr_compatible_resolver_)
779 return make_xr_compatible_resolver_->Promise();
780
781 make_xr_compatible_resolver_ =
782 MakeGarbageCollected<ScriptPromiseResolver>(script_state);
783 ScriptPromise promise = make_xr_compatible_resolver_->Promise();
784
785 MakeXrCompatibleAsync();
786
787 return promise;
788 }
789
IsXRCompatible() const790 bool WebGLRenderingContextBase::IsXRCompatible() const {
791 return xr_compatible_;
792 }
793
IsXrCompatibleFromResult(device::mojom::blink::XrCompatibleResult result)794 bool WebGLRenderingContextBase::IsXrCompatibleFromResult(
795 device::mojom::blink::XrCompatibleResult result) {
796 return result ==
797 device::mojom::blink::XrCompatibleResult::kAlreadyCompatible ||
798 result ==
799 device::mojom::blink::XrCompatibleResult::kCompatibleAfterRestart;
800 }
801
DidGpuRestart(device::mojom::blink::XrCompatibleResult result)802 bool WebGLRenderingContextBase::DidGpuRestart(
803 device::mojom::blink::XrCompatibleResult result) {
804 return result == device::mojom::blink::XrCompatibleResult::
805 kCompatibleAfterRestart ||
806 result == device::mojom::blink::XrCompatibleResult::
807 kNotCompatibleAfterRestart;
808 }
809
MakeXrCompatibleSync(CanvasRenderingContextHost * host)810 bool WebGLRenderingContextBase::MakeXrCompatibleSync(
811 CanvasRenderingContextHost* host) {
812 if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled())
813 return true;
814
815 device::mojom::blink::XrCompatibleResult xr_compatible_result =
816 device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable;
817
818 if (!host->IsOffscreenCanvas()) {
819 HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(host);
820 if (XRSystem* xr = XRSystem::From(canvas->GetDocument()))
821 xr->MakeXrCompatibleSync(&xr_compatible_result);
822 }
823
824 return IsXrCompatibleFromResult(xr_compatible_result);
825 }
826
MakeXrCompatibleAsync()827 void WebGLRenderingContextBase::MakeXrCompatibleAsync() {
828 if (!canvas()) {
829 xr_compatible_ = false;
830 CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
831 return;
832 }
833
834 XRSystem* xr = XRSystem::From(canvas()->GetDocument());
835 if (!xr) {
836 xr_compatible_ = false;
837 CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
838 return;
839 }
840
841 // The promise will be completed on the callback.
842 xr->MakeXrCompatibleAsync(
843 WTF::Bind(&WebGLRenderingContextBase::OnMakeXrCompatibleFinished,
844 WrapWeakPersistent(this)));
845 }
846
OnMakeXrCompatibleFinished(device::mojom::blink::XrCompatibleResult xr_compatible_result)847 void WebGLRenderingContextBase::OnMakeXrCompatibleFinished(
848 device::mojom::blink::XrCompatibleResult xr_compatible_result) {
849 xr_compatible_ = IsXrCompatibleFromResult(xr_compatible_result);
850
851 // If the gpu process is restarted, MaybeRestoreContext will resolve the
852 // promise on the subsequent restore.
853 if (!DidGpuRestart(xr_compatible_result)) {
854 DOMExceptionCode exception_code = DOMExceptionCode::kUnknownError;
855 switch (xr_compatible_result) {
856 case device::mojom::blink::XrCompatibleResult::kAlreadyCompatible:
857 exception_code = DOMExceptionCode::kNoError;
858 break;
859 case device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable:
860 // Per WebXR spec, reject with an InvalidStateError if device is null.
861 exception_code = DOMExceptionCode::kInvalidStateError;
862 break;
863 case device::mojom::blink::XrCompatibleResult::kWebXrFeaturePolicyBlocked:
864 exception_code = DOMExceptionCode::kSecurityError;
865 break;
866 case device::mojom::blink::XrCompatibleResult::kCompatibleAfterRestart:
867 case device::mojom::blink::XrCompatibleResult::kNotCompatibleAfterRestart:
868 NOTREACHED();
869 }
870 CompleteXrCompatiblePromiseIfPending(exception_code);
871 }
872 }
873
CompleteXrCompatiblePromiseIfPending(DOMExceptionCode exception_code)874 void WebGLRenderingContextBase::CompleteXrCompatiblePromiseIfPending(
875 DOMExceptionCode exception_code) {
876 if (make_xr_compatible_resolver_) {
877 if (xr_compatible_) {
878 DCHECK(exception_code == DOMExceptionCode::kNoError);
879 make_xr_compatible_resolver_->Resolve();
880 } else {
881 DCHECK(exception_code != DOMExceptionCode::kNoError);
882 make_xr_compatible_resolver_->Reject(
883 MakeGarbageCollected<DOMException>(exception_code));
884 }
885
886 make_xr_compatible_resolver_ = nullptr;
887
888 if (IdentifiabilityStudySettings::Get()->ShouldSample(
889 IdentifiableSurface::FromTypeAndToken(
890 IdentifiableSurface::Type::kWebFeature,
891 WebFeature::kWebGLRenderingContextMakeXRCompatible))) {
892 const auto& ukm_params = GetUkmParameters();
893 IdentifiabilityMetricBuilder(ukm_params.source_id)
894 .SetWebfeature(WebFeature::kWebGLRenderingContextMakeXRCompatible,
895 exception_code == DOMExceptionCode::kNoError)
896 .Record(ukm_params.ukm_recorder);
897 }
898 }
899 }
900
901 void WebGLRenderingContextBase::
UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta)902 UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta) {
903 DCHECK(delta >= -1 && delta <= 1);
904 number_of_user_allocated_multisampled_renderbuffers_ += delta;
905 DCHECK_GE(number_of_user_allocated_multisampled_renderbuffers_, 0);
906 }
907
908 namespace {
909
910 // Exposed by GL_ANGLE_depth_texture
911 static const GLenum kSupportedInternalFormatsOESDepthTex[] = {
912 GL_DEPTH_COMPONENT,
913 GL_DEPTH_STENCIL,
914 };
915
916 // Exposed by GL_EXT_sRGB
917 static const GLenum kSupportedInternalFormatsEXTsRGB[] = {
918 GL_SRGB,
919 GL_SRGB_ALPHA_EXT,
920 };
921
922 // ES3 enums supported by both CopyTexImage and TexImage.
923 static const GLenum kSupportedInternalFormatsES3[] = {
924 GL_R8, GL_RG8, GL_RGB565, GL_RGB8, GL_RGBA4,
925 GL_RGB5_A1, GL_RGBA8, GL_RGB10_A2, GL_RGB10_A2UI, GL_SRGB8,
926 GL_SRGB8_ALPHA8, GL_R8I, GL_R8UI, GL_R16I, GL_R16UI,
927 GL_R32I, GL_R32UI, GL_RG8I, GL_RG8UI, GL_RG16I,
928 GL_RG16UI, GL_RG32I, GL_RG32UI, GL_RGBA8I, GL_RGBA8UI,
929 GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI, GL_RGB32I,
930 GL_RGB32UI, GL_RGB8I, GL_RGB8UI, GL_RGB16I, GL_RGB16UI,
931 };
932
933 // ES3 enums only supported by TexImage
934 static const GLenum kSupportedInternalFormatsTexImageES3[] = {
935 GL_R8_SNORM,
936 GL_R16F,
937 GL_R32F,
938 GL_RG8_SNORM,
939 GL_RG16F,
940 GL_RG32F,
941 GL_RGB8_SNORM,
942 GL_R11F_G11F_B10F,
943 GL_RGB9_E5,
944 GL_RGB16F,
945 GL_RGB32F,
946 GL_RGBA8_SNORM,
947 GL_RGBA16F,
948 GL_RGBA32F,
949 GL_DEPTH_COMPONENT16,
950 GL_DEPTH_COMPONENT24,
951 GL_DEPTH_COMPONENT32F,
952 GL_DEPTH24_STENCIL8,
953 GL_DEPTH32F_STENCIL8,
954 };
955
956 // Exposed by EXT_texture_norm16
957 static constexpr GLenum kSupportedInternalFormatsEXTTextureNorm16ES3[] = {
958 GL_R16_EXT, GL_RG16_EXT, GL_RGB16_EXT,
959 GL_RGBA16_EXT, GL_R16_SNORM_EXT, GL_RG16_SNORM_EXT,
960 GL_RGB16_SNORM_EXT, GL_RGBA16_SNORM_EXT};
961
962 static constexpr GLenum kSupportedFormatsEXTTextureNorm16ES3[] = {GL_RED,
963 GL_RG};
964
965 static constexpr GLenum kSupportedTypesEXTTextureNorm16ES3[] = {
966 GL_SHORT, GL_UNSIGNED_SHORT};
967
968 // Exposed by EXT_color_buffer_float
969 static const GLenum kSupportedInternalFormatsCopyTexImageFloatES3[] = {
970 GL_R16F, GL_R32F, GL_RG16F, GL_RG32F, GL_RGB16F,
971 GL_RGB32F, GL_RGBA16F, GL_RGBA32F, GL_R11F_G11F_B10F};
972
973 // Exposed by EXT_color_buffer_half_float
974 static const GLenum kSupportedInternalFormatsCopyTexImageHalfFloatES3[] = {
975 GL_R16F,
976 GL_RG16F,
977 GL_RGB16F,
978 GL_RGBA16F,
979 };
980
981 // ES3 enums supported by TexImageSource
982 static const GLenum kSupportedInternalFormatsTexImageSourceES3[] = {
983 GL_R8, GL_R16F, GL_R32F, GL_R8UI, GL_RG8,
984 GL_RG16F, GL_RG32F, GL_RG8UI, GL_RGB8, GL_SRGB8,
985 GL_RGB565, GL_R11F_G11F_B10F, GL_RGB9_E5, GL_RGB16F, GL_RGB32F,
986 GL_RGB8UI, GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGB5_A1, GL_RGBA4,
987 GL_RGBA16F, GL_RGBA32F, GL_RGBA8UI, GL_RGB10_A2,
988 };
989
990 // ES2 enums
991 // Internalformat must equal format in ES2.
992 static const GLenum kSupportedFormatsES2[] = {
993 GL_RGB, GL_RGBA, GL_LUMINANCE_ALPHA, GL_LUMINANCE, GL_ALPHA,
994 };
995
996 // Exposed by GL_ANGLE_depth_texture
997 static const GLenum kSupportedFormatsOESDepthTex[] = {
998 GL_DEPTH_COMPONENT,
999 GL_DEPTH_STENCIL,
1000 };
1001
1002 // Exposed by GL_EXT_sRGB
1003 static const GLenum kSupportedFormatsEXTsRGB[] = {
1004 GL_SRGB,
1005 GL_SRGB_ALPHA_EXT,
1006 };
1007
1008 // ES3 enums
1009 static const GLenum kSupportedFormatsES3[] = {
1010 GL_RED, GL_RED_INTEGER, GL_RG,
1011 GL_RG_INTEGER, GL_RGB, GL_RGB_INTEGER,
1012 GL_RGBA, GL_RGBA_INTEGER, GL_DEPTH_COMPONENT,
1013 GL_DEPTH_STENCIL,
1014 };
1015
1016 // ES3 enums supported by TexImageSource
1017 static const GLenum kSupportedFormatsTexImageSourceES3[] = {
1018 GL_RED, GL_RED_INTEGER, GL_RG, GL_RG_INTEGER,
1019 GL_RGB, GL_RGB_INTEGER, GL_RGBA, GL_RGBA_INTEGER,
1020 };
1021
1022 // ES2 enums
1023 static const GLenum kSupportedTypesES2[] = {
1024 GL_UNSIGNED_BYTE,
1025 GL_UNSIGNED_SHORT_5_6_5,
1026 GL_UNSIGNED_SHORT_4_4_4_4,
1027 GL_UNSIGNED_SHORT_5_5_5_1,
1028 };
1029
1030 // Exposed by GL_OES_texture_float
1031 static const GLenum kSupportedTypesOESTexFloat[] = {
1032 GL_FLOAT,
1033 };
1034
1035 // Exposed by GL_OES_texture_half_float
1036 static const GLenum kSupportedTypesOESTexHalfFloat[] = {
1037 GL_HALF_FLOAT_OES,
1038 };
1039
1040 // Exposed by GL_ANGLE_depth_texture
1041 static const GLenum kSupportedTypesOESDepthTex[] = {
1042 GL_UNSIGNED_SHORT,
1043 GL_UNSIGNED_INT,
1044 GL_UNSIGNED_INT_24_8,
1045 };
1046
1047 // ES3 enums
1048 static const GLenum kSupportedTypesES3[] = {
1049 GL_BYTE,
1050 GL_UNSIGNED_SHORT,
1051 GL_SHORT,
1052 GL_UNSIGNED_INT,
1053 GL_INT,
1054 GL_HALF_FLOAT,
1055 GL_FLOAT,
1056 GL_UNSIGNED_INT_2_10_10_10_REV,
1057 GL_UNSIGNED_INT_10F_11F_11F_REV,
1058 GL_UNSIGNED_INT_5_9_9_9_REV,
1059 GL_UNSIGNED_INT_24_8,
1060 GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
1061 };
1062
1063 // ES3 enums supported by TexImageSource
1064 static const GLenum kSupportedTypesTexImageSourceES3[] = {
1065 GL_HALF_FLOAT,
1066 GL_FLOAT,
1067 GL_UNSIGNED_INT_10F_11F_11F_REV,
1068 GL_UNSIGNED_INT_2_10_10_10_REV,
1069 };
1070
1071 } // namespace
1072
WebGLRenderingContextBase(CanvasRenderingContextHost * host,std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing,const CanvasContextCreationAttributesCore & requested_attributes,Platform::ContextType version)1073 WebGLRenderingContextBase::WebGLRenderingContextBase(
1074 CanvasRenderingContextHost* host,
1075 std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
1076 bool using_gpu_compositing,
1077 const CanvasContextCreationAttributesCore& requested_attributes,
1078 Platform::ContextType version)
1079 : WebGLRenderingContextBase(
1080 host,
1081 host->GetTopExecutionContext()->GetTaskRunner(TaskType::kWebGL),
1082 std::move(context_provider),
1083 using_gpu_compositing,
1084 requested_attributes,
1085 version) {}
1086
WebGLRenderingContextBase(CanvasRenderingContextHost * host,scoped_refptr<base::SingleThreadTaskRunner> task_runner,std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing,const CanvasContextCreationAttributesCore & requested_attributes,Platform::ContextType context_type)1087 WebGLRenderingContextBase::WebGLRenderingContextBase(
1088 CanvasRenderingContextHost* host,
1089 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
1090 std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
1091 bool using_gpu_compositing,
1092 const CanvasContextCreationAttributesCore& requested_attributes,
1093 Platform::ContextType context_type)
1094 : CanvasRenderingContext(host, requested_attributes),
1095 context_group_(MakeGarbageCollected<WebGLContextGroup>()),
1096 dispatch_context_lost_event_timer_(
1097 task_runner,
1098 this,
1099 &WebGLRenderingContextBase::DispatchContextLostEvent),
1100 restore_timer_(task_runner,
1101 this,
1102 &WebGLRenderingContextBase::MaybeRestoreContext),
1103 task_runner_(task_runner),
1104 num_gl_errors_to_console_allowed_(kMaxGLErrorsAllowedToConsole),
1105 context_type_(context_type),
1106 program_completion_queries_(
1107 base::MRUCache<WebGLProgram*, GLuint>::NO_AUTO_EVICT),
1108 number_of_user_allocated_multisampled_renderbuffers_(0) {
1109 DCHECK(context_provider);
1110
1111 xr_compatible_ = requested_attributes.xr_compatible;
1112
1113 context_group_->AddContext(this);
1114
1115 max_viewport_dims_[0] = max_viewport_dims_[1] = 0;
1116 context_provider->ContextGL()->GetIntegerv(GL_MAX_VIEWPORT_DIMS,
1117 max_viewport_dims_);
1118 InitializeWebGLContextLimits(context_provider.get());
1119
1120 scoped_refptr<DrawingBuffer> buffer;
1121 buffer =
1122 CreateDrawingBuffer(std::move(context_provider), using_gpu_compositing);
1123 if (!buffer) {
1124 context_lost_mode_ = kSyntheticLostContext;
1125 return;
1126 }
1127
1128 drawing_buffer_ = std::move(buffer);
1129 GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
1130 SetupFlags();
1131
1132 String disabled_webgl_extensions(GetDrawingBuffer()
1133 ->ContextProvider()
1134 ->GetGpuFeatureInfo()
1135 .disabled_webgl_extensions.c_str());
1136 Vector<String> disabled_extension_list;
1137 disabled_webgl_extensions.Split(' ', disabled_extension_list);
1138 for (const auto& entry : disabled_extension_list) {
1139 disabled_extensions_.insert(entry);
1140 }
1141
1142 #define ADD_VALUES_TO_SET(set, values) \
1143 for (size_t i = 0; i < base::size(values); ++i) { \
1144 set.insert(values[i]); \
1145 }
1146
1147 ADD_VALUES_TO_SET(supported_internal_formats_, kSupportedFormatsES2);
1148 ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
1149 kSupportedFormatsES2);
1150 ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
1151 kSupportedFormatsES2);
1152 ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsES2);
1153 ADD_VALUES_TO_SET(supported_tex_image_source_formats_, kSupportedFormatsES2);
1154 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesES2);
1155 ADD_VALUES_TO_SET(supported_tex_image_source_types_, kSupportedTypesES2);
1156 }
1157
CreateDrawingBuffer(std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing)1158 scoped_refptr<DrawingBuffer> WebGLRenderingContextBase::CreateDrawingBuffer(
1159 std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
1160 bool using_gpu_compositing) {
1161 const CanvasContextCreationAttributesCore& attrs = CreationAttributes();
1162 bool premultiplied_alpha = attrs.premultiplied_alpha;
1163 bool want_alpha_channel = attrs.alpha;
1164 bool want_depth_buffer = attrs.depth;
1165 bool want_stencil_buffer = attrs.stencil;
1166 bool want_antialiasing = attrs.antialias;
1167 DrawingBuffer::PreserveDrawingBuffer preserve = attrs.preserve_drawing_buffer
1168 ? DrawingBuffer::kPreserve
1169 : DrawingBuffer::kDiscard;
1170 DrawingBuffer::WebGLVersion web_gl_version = DrawingBuffer::kWebGL1;
1171 if (context_type_ == Platform::kWebGL1ContextType) {
1172 web_gl_version = DrawingBuffer::kWebGL1;
1173 } else if (context_type_ == Platform::kWebGL2ContextType) {
1174 web_gl_version = DrawingBuffer::kWebGL2;
1175 } else {
1176 NOTREACHED();
1177 }
1178
1179 // On Mac OS, DrawingBuffer is using an IOSurface as its backing storage, this
1180 // allows WebGL-rendered canvases to be composited by the OS rather than
1181 // Chrome.
1182 // IOSurfaces are only compatible with the GL_TEXTURE_RECTANGLE_ARB binding
1183 // target. So to avoid the knowledge of GL_TEXTURE_RECTANGLE_ARB type textures
1184 // being introduced into more areas of the code, we use the code path of
1185 // non-WebGLImageChromium for OffscreenCanvas.
1186 // See detailed discussion in crbug.com/649668.
1187 DrawingBuffer::ChromiumImageUsage chromium_image_usage =
1188 Host()->IsOffscreenCanvas() ? DrawingBuffer::kDisallowChromiumImage
1189 : DrawingBuffer::kAllowChromiumImage;
1190
1191 bool using_swap_chain =
1192 base::FeatureList::IsEnabled(features::kLowLatencyWebGLSwapChain) &&
1193 context_provider->GetCapabilities().shared_image_swap_chain &&
1194 attrs.desynchronized;
1195
1196 return DrawingBuffer::Create(
1197 std::move(context_provider), using_gpu_compositing, using_swap_chain,
1198 this, ClampedCanvasSize(), premultiplied_alpha, want_alpha_channel,
1199 want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve,
1200 web_gl_version, chromium_image_usage, Host()->FilterQuality(),
1201 ColorParams(), PowerPreferenceToGpuPreference(attrs.power_preference));
1202 }
1203
InitializeNewContext()1204 void WebGLRenderingContextBase::InitializeNewContext() {
1205 DCHECK(!isContextLost());
1206 DCHECK(GetDrawingBuffer());
1207
1208 marked_canvas_dirty_ = false;
1209 must_paint_to_canvas_ = false;
1210 active_texture_unit_ = 0;
1211 pack_alignment_ = 4;
1212 unpack_alignment_ = 4;
1213 unpack_flip_y_ = false;
1214 unpack_premultiply_alpha_ = false;
1215 unpack_colorspace_conversion_ = GC3D_BROWSER_DEFAULT_WEBGL;
1216 bound_array_buffer_ = nullptr;
1217 current_program_ = nullptr;
1218 framebuffer_binding_ = nullptr;
1219 renderbuffer_binding_ = nullptr;
1220 depth_mask_ = true;
1221 stencil_enabled_ = false;
1222 stencil_mask_ = 0xFFFFFFFF;
1223 stencil_mask_back_ = 0xFFFFFFFF;
1224 stencil_func_ref_ = 0;
1225 stencil_func_ref_back_ = 0;
1226 stencil_func_mask_ = 0xFFFFFFFF;
1227 stencil_func_mask_back_ = 0xFFFFFFFF;
1228 num_gl_errors_to_console_allowed_ = kMaxGLErrorsAllowedToConsole;
1229
1230 clear_color_[0] = clear_color_[1] = clear_color_[2] = clear_color_[3] = 0;
1231 scissor_enabled_ = false;
1232 clear_depth_ = 1;
1233 clear_stencil_ = 0;
1234 color_mask_[0] = color_mask_[1] = color_mask_[2] = color_mask_[3] = true;
1235
1236 GLint num_combined_texture_image_units = 0;
1237 ContextGL()->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
1238 &num_combined_texture_image_units);
1239 texture_units_.clear();
1240 texture_units_.resize(num_combined_texture_image_units);
1241
1242 GLint num_vertex_attribs = 0;
1243 ContextGL()->GetIntegerv(GL_MAX_VERTEX_ATTRIBS, &num_vertex_attribs);
1244 max_vertex_attribs_ = num_vertex_attribs;
1245
1246 max_texture_size_ = 0;
1247 ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1248 max_texture_level_ =
1249 WebGLTexture::ComputeLevelCount(max_texture_size_, max_texture_size_, 1);
1250 max_cube_map_texture_size_ = 0;
1251 ContextGL()->GetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE,
1252 &max_cube_map_texture_size_);
1253 max3d_texture_size_ = 0;
1254 max3d_texture_level_ = 0;
1255 max_array_texture_layers_ = 0;
1256 if (IsWebGL2()) {
1257 ContextGL()->GetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3d_texture_size_);
1258 max3d_texture_level_ = WebGLTexture::ComputeLevelCount(
1259 max3d_texture_size_, max3d_texture_size_, max3d_texture_size_);
1260 ContextGL()->GetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS,
1261 &max_array_texture_layers_);
1262 }
1263 max_cube_map_texture_level_ = WebGLTexture::ComputeLevelCount(
1264 max_cube_map_texture_size_, max_cube_map_texture_size_, 1);
1265 max_renderbuffer_size_ = 0;
1266 ContextGL()->GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &max_renderbuffer_size_);
1267
1268 // These two values from EXT_draw_buffers are lazily queried.
1269 max_draw_buffers_ = 0;
1270 max_color_attachments_ = 0;
1271
1272 back_draw_buffer_ = GL_BACK;
1273
1274 read_buffer_of_default_framebuffer_ = GL_BACK;
1275
1276 default_vertex_array_object_ = MakeGarbageCollected<WebGLVertexArrayObject>(
1277 this, WebGLVertexArrayObjectBase::kVaoTypeDefault);
1278
1279 bound_vertex_array_object_ = default_vertex_array_object_;
1280
1281 vertex_attrib_type_.resize(max_vertex_attribs_);
1282
1283 ContextGL()->Viewport(0, 0, drawingBufferWidth(), drawingBufferHeight());
1284 scissor_box_[0] = scissor_box_[1] = 0;
1285 scissor_box_[2] = drawingBufferWidth();
1286 scissor_box_[3] = drawingBufferHeight();
1287 ContextGL()->Scissor(scissor_box_[0], scissor_box_[1], scissor_box_[2],
1288 scissor_box_[3]);
1289
1290 GetDrawingBuffer()->ContextProvider()->SetLostContextCallback(
1291 WTF::BindRepeating(&WebGLRenderingContextBase::ForceLostContext,
1292 WrapWeakPersistent(this),
1293 WebGLRenderingContextBase::kRealLostContext,
1294 WebGLRenderingContextBase::kAuto));
1295 GetDrawingBuffer()->ContextProvider()->SetErrorMessageCallback(
1296 WTF::BindRepeating(&WebGLRenderingContextBase::OnErrorMessage,
1297 WrapWeakPersistent(this)));
1298
1299 // If the context has the flip_y extension, it will behave as having the
1300 // origin of coordinates on the top left.
1301 is_origin_top_left_ = GetDrawingBuffer()
1302 ->ContextProvider()
1303 ->GetCapabilities()
1304 .mesa_framebuffer_flip_y;
1305
1306 // If WebGL 2, the PRIMITIVE_RESTART_FIXED_INDEX should be always enabled.
1307 // See the section <Primitive Restart is Always Enabled> in WebGL 2 spec:
1308 // https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.4
1309 if (IsWebGL2())
1310 ContextGL()->Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
1311
1312 // This ensures that the context has a valid "lastFlushID" and won't be
1313 // mistakenly identified as the "least recently used" context.
1314 ContextGL()->Flush();
1315
1316 for (int i = 0; i < kWebGLExtensionNameCount; ++i)
1317 extension_enabled_[i] = false;
1318
1319 // This limits the count of threads if the extension is yet to be requested.
1320 if (String(ContextGL()->GetString(GL_EXTENSIONS))
1321 .Contains("GL_KHR_parallel_shader_compile")) {
1322 ContextGL()->MaxShaderCompilerThreadsKHR(2);
1323 }
1324 is_web_gl2_formats_types_added_ = false;
1325 is_web_gl2_tex_image_source_formats_types_added_ = false;
1326 is_web_gl2_internal_formats_copy_tex_image_added_ = false;
1327 is_oes_texture_float_formats_types_added_ = false;
1328 is_oes_texture_half_float_formats_types_added_ = false;
1329 is_web_gl_depth_texture_formats_types_added_ = false;
1330 is_ext_srgb_formats_types_added_ = false;
1331 is_ext_color_buffer_float_formats_added_ = false;
1332 is_ext_color_buffer_half_float_formats_added_ = false;
1333 is_ext_texture_norm16_added_ = false;
1334
1335 supported_internal_formats_.clear();
1336 ADD_VALUES_TO_SET(supported_internal_formats_, kSupportedFormatsES2);
1337 supported_tex_image_source_internal_formats_.clear();
1338 ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
1339 kSupportedFormatsES2);
1340 supported_internal_formats_copy_tex_image_.clear();
1341 ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
1342 kSupportedFormatsES2);
1343 supported_formats_.clear();
1344 ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsES2);
1345 supported_tex_image_source_formats_.clear();
1346 ADD_VALUES_TO_SET(supported_tex_image_source_formats_, kSupportedFormatsES2);
1347 supported_types_.clear();
1348 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesES2);
1349 supported_tex_image_source_types_.clear();
1350 ADD_VALUES_TO_SET(supported_tex_image_source_types_, kSupportedTypesES2);
1351
1352 number_of_user_allocated_multisampled_renderbuffers_ = 0;
1353
1354 // The DrawingBuffer was unable to store the state that dirtied when it was
1355 // initialized. Restore it now.
1356 GetDrawingBuffer()->RestoreAllState();
1357 ActivateContext(this);
1358 }
1359
SetupFlags()1360 void WebGLRenderingContextBase::SetupFlags() {
1361 DCHECK(GetDrawingBuffer());
1362 if (canvas()) {
1363 synthesized_errors_to_console_ =
1364 canvas()->GetSettings()->GetWebGLErrorsToConsoleEnabled();
1365 }
1366
1367 is_depth_stencil_supported_ =
1368 ExtensionsUtil()->IsExtensionEnabled("GL_OES_packed_depth_stencil");
1369 }
1370
AddCompressedTextureFormat(GLenum format)1371 void WebGLRenderingContextBase::AddCompressedTextureFormat(GLenum format) {
1372 if (!compressed_texture_formats_.Contains(format))
1373 compressed_texture_formats_.push_back(format);
1374 }
1375
RemoveAllCompressedTextureFormats()1376 void WebGLRenderingContextBase::RemoveAllCompressedTextureFormats() {
1377 compressed_texture_formats_.clear();
1378 }
1379
1380 // Helper function for V8 bindings to identify what version of WebGL a
1381 // CanvasRenderingContext supports.
GetWebGLVersion(const CanvasRenderingContext * context)1382 unsigned WebGLRenderingContextBase::GetWebGLVersion(
1383 const CanvasRenderingContext* context) {
1384 if (!context->Is3d())
1385 return 0;
1386 return static_cast<const WebGLRenderingContextBase*>(context)->ContextType();
1387 }
1388
~WebGLRenderingContextBase()1389 WebGLRenderingContextBase::~WebGLRenderingContextBase() {
1390 // It's forbidden to refer to other GC'd objects in a GC'd object's
1391 // destructor. It's useful for DrawingBuffer to guarantee that it
1392 // calls its DrawingBufferClient during its own destruction, but if
1393 // the WebGL context is also being destroyed, then it's essential
1394 // that the DrawingBufferClient methods not try to touch other
1395 // objects like WebGLTextures that were previously hooked into the
1396 // context state.
1397 destruction_in_progress_ = true;
1398
1399 // Now that the context and context group no longer hold on to the
1400 // objects they create, and now that the objects are eagerly finalized
1401 // rather than the context, there is very little useful work that this
1402 // destructor can do, since it's not allowed to touch other on-heap
1403 // objects. All it can do is destroy its underlying context, which, if
1404 // there are no other contexts in the same share group, will cause all of
1405 // the underlying graphics resources to be deleted. (Currently, it's
1406 // always the case that there are no other contexts in the same share
1407 // group -- resource sharing between WebGL contexts is not yet
1408 // implemented, and due to its complex semantics, it's doubtful that it
1409 // ever will be.)
1410 DestroyContext();
1411
1412 // Now that this context is destroyed, see if there's a
1413 // previously-evicted one that should be restored.
1414 RestoreEvictedContext(this);
1415 }
1416
DestroyContext()1417 void WebGLRenderingContextBase::DestroyContext() {
1418 if (!GetDrawingBuffer())
1419 return;
1420
1421 clearProgramCompletionQueries();
1422
1423 extensions_util_.reset();
1424
1425 base::RepeatingClosure null_closure;
1426 base::RepeatingCallback<void(const char*, int32_t)> null_function;
1427 GetDrawingBuffer()->ContextProvider()->SetLostContextCallback(
1428 std::move(null_closure));
1429 GetDrawingBuffer()->ContextProvider()->SetErrorMessageCallback(
1430 std::move(null_function));
1431
1432 DCHECK(GetDrawingBuffer());
1433 drawing_buffer_->BeginDestruction();
1434 drawing_buffer_ = nullptr;
1435 }
1436
MarkContextChanged(ContentChangeType change_type)1437 void WebGLRenderingContextBase::MarkContextChanged(
1438 ContentChangeType change_type) {
1439 if (isContextLost())
1440 return;
1441
1442 if (framebuffer_binding_) {
1443 framebuffer_binding_->SetContentsChanged(true);
1444 return;
1445 }
1446
1447 // Regardless of whether dirty propagations are optimized away, the back
1448 // buffer is now out of sync with respect to the canvas's internal backing
1449 // store -- which is only used for certain purposes, like printing.
1450 must_paint_to_canvas_ = true;
1451
1452 if (!GetDrawingBuffer()->MarkContentsChanged() && marked_canvas_dirty_) {
1453 return;
1454 }
1455
1456 if (Host()->IsOffscreenCanvas()) {
1457 marked_canvas_dirty_ = true;
1458 DidDraw();
1459 return;
1460 }
1461
1462 if (!canvas())
1463 return;
1464
1465 if (!marked_canvas_dirty_) {
1466 marked_canvas_dirty_ = true;
1467 LayoutBox* layout_box = canvas()->GetLayoutBox();
1468 auto* settings = canvas()->GetDocument().GetSettings();
1469 if (layout_box && settings->GetAcceleratedCompositingEnabled())
1470 layout_box->ContentChanged(change_type);
1471 IntSize canvas_size = ClampedCanvasSize();
1472 DidDraw(SkIRect::MakeXYWH(0, 0, canvas_size.Width(), canvas_size.Height()));
1473 }
1474 }
1475
1476 scoped_refptr<base::SingleThreadTaskRunner>
GetContextTaskRunner()1477 WebGLRenderingContextBase::GetContextTaskRunner() {
1478 return task_runner_;
1479 }
1480
DidDraw(const SkIRect & dirty_rect)1481 void WebGLRenderingContextBase::DidDraw(const SkIRect& dirty_rect) {
1482 MarkContextChanged(kCanvasChanged);
1483 CanvasRenderingContext::DidDraw(dirty_rect);
1484 }
1485
DidDraw()1486 void WebGLRenderingContextBase::DidDraw() {
1487 MarkContextChanged(kCanvasChanged);
1488 CanvasRenderingContext::DidDraw();
1489 }
1490
PushFrame()1491 bool WebGLRenderingContextBase::PushFrame() {
1492 int submitted_frame = false;
1493 if (PaintRenderingResultsToCanvas(kBackBuffer)) {
1494 if (Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU)) {
1495 int width = GetDrawingBuffer()->Size().Width();
1496 int height = GetDrawingBuffer()->Size().Height();
1497 submitted_frame =
1498 Host()->PushFrame(Host()->ResourceProvider()->ProduceCanvasResource(),
1499 SkIRect::MakeWH(width, height));
1500 }
1501 }
1502 MarkLayerComposited();
1503 return submitted_frame;
1504 }
1505
FinalizeFrame()1506 void WebGLRenderingContextBase::FinalizeFrame() {
1507 if (Host()->LowLatencyEnabled()) {
1508 // PaintRenderingResultsToCanvas will export drawing buffer if the resource
1509 // provider is single buffered. Otherwise it will copy the drawing buffer.
1510 PaintRenderingResultsToCanvas(kBackBuffer);
1511 }
1512 marked_canvas_dirty_ = false;
1513 }
1514
OnErrorMessage(const char * message,int32_t id)1515 void WebGLRenderingContextBase::OnErrorMessage(const char* message,
1516 int32_t id) {
1517 if (synthesized_errors_to_console_)
1518 PrintGLErrorToConsole(message);
1519 NotifyWebGLErrorOrWarning(message);
1520 }
1521
1522 WebGLRenderingContextBase::HowToClear
ClearIfComposited(GLbitfield mask)1523 WebGLRenderingContextBase::ClearIfComposited(GLbitfield mask) {
1524 if (isContextLost())
1525 return kSkipped;
1526
1527 GLbitfield buffers_needing_clearing =
1528 GetDrawingBuffer()->GetBuffersToAutoClear();
1529
1530 if (buffers_needing_clearing == 0 || (mask && framebuffer_binding_))
1531 return kSkipped;
1532
1533 if (isContextLost()) {
1534 // Unlikely, but context was lost.
1535 return kSkipped;
1536 }
1537
1538 // Determine if it's possible to combine the clear the user asked for and this
1539 // clear.
1540 bool combined_clear = mask && !scissor_enabled_;
1541
1542 ContextGL()->Disable(GL_SCISSOR_TEST);
1543 if (combined_clear && (mask & GL_COLOR_BUFFER_BIT)) {
1544 ContextGL()->ClearColor(color_mask_[0] ? clear_color_[0] : 0,
1545 color_mask_[1] ? clear_color_[1] : 0,
1546 color_mask_[2] ? clear_color_[2] : 0,
1547 color_mask_[3] ? clear_color_[3] : 0);
1548 } else {
1549 ContextGL()->ClearColor(0, 0, 0, 0);
1550 }
1551 ContextGL()->ColorMask(
1552 true, true, true,
1553 !GetDrawingBuffer()->RequiresAlphaChannelToBePreserved());
1554 GLbitfield clear_mask = GL_COLOR_BUFFER_BIT;
1555
1556 const bool has_depth =
1557 CreationAttributes().depth && GetDrawingBuffer()->HasDepthBuffer();
1558 const bool has_stencil =
1559 CreationAttributes().stencil && GetDrawingBuffer()->HasStencilBuffer();
1560
1561 if (has_depth) {
1562 if (!combined_clear || !depth_mask_ || !(mask & GL_DEPTH_BUFFER_BIT))
1563 ContextGL()->ClearDepthf(1.0f);
1564 clear_mask |= GL_DEPTH_BUFFER_BIT;
1565 ContextGL()->DepthMask(true);
1566 }
1567 if (has_stencil || GetDrawingBuffer()->HasImplicitStencilBuffer()) {
1568 if (combined_clear && (mask & GL_STENCIL_BUFFER_BIT))
1569 ContextGL()->ClearStencil(clear_stencil_ & stencil_mask_);
1570 else
1571 ContextGL()->ClearStencil(0);
1572 clear_mask |= GL_STENCIL_BUFFER_BIT;
1573 ContextGL()->StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
1574 }
1575
1576 ContextGL()->ColorMask(
1577 true, true, true,
1578 !GetDrawingBuffer()->DefaultBufferRequiresAlphaChannelToBePreserved());
1579 // If the WebGL 2.0 clearBuffer APIs already have been used to
1580 // selectively clear some of the buffers, don't destroy those
1581 // results.
1582 GetDrawingBuffer()->ClearFramebuffers(clear_mask & buffers_needing_clearing);
1583
1584 // Call the DrawingBufferClient method to restore scissor test, mask, and
1585 // clear values, because we dirtied them above.
1586 DrawingBufferClientRestoreScissorTest();
1587 DrawingBufferClientRestoreMaskAndClearValues();
1588
1589 GetDrawingBuffer()->SetBuffersToAutoClear(0);
1590
1591 return combined_clear ? kCombinedClear : kJustClear;
1592 }
1593
RestoreScissorEnabled()1594 void WebGLRenderingContextBase::RestoreScissorEnabled() {
1595 if (isContextLost())
1596 return;
1597
1598 if (scissor_enabled_) {
1599 ContextGL()->Enable(GL_SCISSOR_TEST);
1600 } else {
1601 ContextGL()->Disable(GL_SCISSOR_TEST);
1602 }
1603 }
1604
RestoreScissorBox()1605 void WebGLRenderingContextBase::RestoreScissorBox() {
1606 if (isContextLost())
1607 return;
1608
1609 ContextGL()->Scissor(scissor_box_[0], scissor_box_[1], scissor_box_[2],
1610 scissor_box_[3]);
1611 }
1612
RestoreClearColor()1613 void WebGLRenderingContextBase::RestoreClearColor() {
1614 if (isContextLost())
1615 return;
1616
1617 ContextGL()->ClearColor(clear_color_[0], clear_color_[1], clear_color_[2],
1618 clear_color_[3]);
1619 }
1620
RestoreColorMask()1621 void WebGLRenderingContextBase::RestoreColorMask() {
1622 if (isContextLost())
1623 return;
1624
1625 ContextGL()->ColorMask(color_mask_[0], color_mask_[1], color_mask_[2],
1626 color_mask_[3]);
1627 }
1628
MarkLayerComposited()1629 void WebGLRenderingContextBase::MarkLayerComposited() {
1630 if (!isContextLost())
1631 GetDrawingBuffer()->ResetBuffersToAutoClear();
1632 }
1633
UsingSwapChain() const1634 bool WebGLRenderingContextBase::UsingSwapChain() const {
1635 return GetDrawingBuffer() && GetDrawingBuffer()->UsingSwapChain();
1636 }
1637
IsOriginTopLeft() const1638 bool WebGLRenderingContextBase::IsOriginTopLeft() const {
1639 if (isContextLost())
1640 return false;
1641 return is_origin_top_left_;
1642 }
1643
SetIsInHiddenPage(bool hidden)1644 void WebGLRenderingContextBase::SetIsInHiddenPage(bool hidden) {
1645 is_hidden_ = hidden;
1646 if (GetDrawingBuffer())
1647 GetDrawingBuffer()->SetIsInHiddenPage(hidden);
1648
1649 if (!hidden && isContextLost() && restore_allowed_ &&
1650 auto_recovery_method_ == kAuto && !restore_timer_.IsActive()) {
1651 restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
1652 }
1653 }
1654
PaintRenderingResultsToCanvas(SourceDrawingBuffer source_buffer)1655 bool WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
1656 SourceDrawingBuffer source_buffer) {
1657 if (isContextLost() || !GetDrawingBuffer())
1658 return false;
1659
1660 bool must_clear_now = ClearIfComposited() != kSkipped;
1661 if (!must_paint_to_canvas_ && !must_clear_now)
1662 return false;
1663
1664 must_paint_to_canvas_ = false;
1665
1666 if (Host()->ResourceProvider() &&
1667 Host()->ResourceProvider()->Size() != GetDrawingBuffer()->Size()) {
1668 Host()->DiscardResourceProvider();
1669 }
1670
1671 CanvasResourceProvider* resource_provider =
1672 Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU);
1673 if (!resource_provider)
1674 return false;
1675
1676 if (Host()->LowLatencyEnabled() &&
1677 resource_provider->SupportsSingleBuffering()) {
1678 // It's possible single buffering isn't enabled yet because we haven't
1679 // finished the first frame e.g. this gets called first due to drawImage.
1680 resource_provider->TryEnableSingleBuffering();
1681 DCHECK(resource_provider->IsSingleBuffered());
1682 // Single buffered passthrough resource provider doesn't have backing
1683 // texture. We need to export the backbuffer mailbox directly without
1684 // copying.
1685 if (!resource_provider->ImportResource(GetDrawingBuffer()->AsCanvasResource(
1686 resource_provider->CreateWeakPtr()))) {
1687 // This isn't expected to fail for single buffered resource provider.
1688 NOTREACHED();
1689 return false;
1690 }
1691 return true;
1692 }
1693
1694 ScopedTexture2DRestorer restorer(this);
1695 ScopedFramebufferRestorer fbo_restorer(this);
1696
1697 GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
1698 if (!CopyRenderingResultsFromDrawingBuffer(Host()->ResourceProvider(),
1699 source_buffer)) {
1700 // Currently, CopyRenderingResultsFromDrawingBuffer is expected to always
1701 // succeed because cases where canvas()-buffer() is not accelerated are
1702 // handled before reaching this point. If that assumption ever stops
1703 // holding true, we may need to implement a fallback right here.
1704 NOTREACHED();
1705 return false;
1706 }
1707 return true;
1708 }
1709
CopyRenderingResultsFromDrawingBuffer(CanvasResourceProvider * resource_provider,SourceDrawingBuffer source_buffer)1710 bool WebGLRenderingContextBase::CopyRenderingResultsFromDrawingBuffer(
1711 CanvasResourceProvider* resource_provider,
1712 SourceDrawingBuffer source_buffer) {
1713 DCHECK(drawing_buffer_);
1714 DCHECK(resource_provider);
1715 DCHECK(!resource_provider->IsSingleBuffered());
1716 if (resource_provider->IsAccelerated()) {
1717 base::WeakPtr<WebGraphicsContext3DProviderWrapper> shared_context_wrapper =
1718 SharedGpuContext::ContextProviderWrapper();
1719 if (!shared_context_wrapper || !shared_context_wrapper->ContextProvider())
1720 return false;
1721 gpu::raster::RasterInterface* raster_interface =
1722 shared_context_wrapper->ContextProvider()->RasterInterface();
1723 const gpu::Mailbox& mailbox =
1724 resource_provider->GetBackingMailboxForOverwrite(
1725 MailboxSyncMode::kOrderingBarrier);
1726 GLenum texture_target = resource_provider->GetBackingTextureTarget();
1727 if (mailbox.IsZero())
1728 return false;
1729
1730 // TODO(xlai): Flush should not be necessary if the synchronization in
1731 // CopyToPlatformTexture is done correctly. See crbug.com/794706.
1732 raster_interface->Flush();
1733
1734 bool flip_y = IsOriginTopLeft() != resource_provider->IsOriginTopLeft();
1735 return drawing_buffer_->CopyToPlatformMailbox(
1736 raster_interface, mailbox, texture_target, flip_y, IntPoint(0, 0),
1737 IntRect(IntPoint(0, 0), drawing_buffer_->Size()), source_buffer);
1738 }
1739
1740 // Note: This code path could work for all cases. The only reason there
1741 // is a separate path for the accelerated case is that we assume texture
1742 // copying is faster than drawImage.
1743 scoped_refptr<StaticBitmapImage> image = GetImage();
1744 if (!image || !image->PaintImageForCurrentFrame())
1745 return false;
1746 cc::PaintFlags paint_flags;
1747 paint_flags.setBlendMode(SkBlendMode::kSrc);
1748 resource_provider->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0,
1749 0, &paint_flags);
1750 return true;
1751 }
1752
DrawingBufferSize() const1753 IntSize WebGLRenderingContextBase::DrawingBufferSize() const {
1754 if (isContextLost())
1755 return IntSize(0, 0);
1756 return GetDrawingBuffer()->Size();
1757 }
1758
PaintRenderingResultsToDataArray(SourceDrawingBuffer source_buffer)1759 sk_sp<SkData> WebGLRenderingContextBase::PaintRenderingResultsToDataArray(
1760 SourceDrawingBuffer source_buffer) {
1761 if (isContextLost())
1762 return nullptr;
1763 ClearIfComposited();
1764 GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
1765 ScopedFramebufferRestorer restorer(this);
1766 return GetDrawingBuffer()->PaintRenderingResultsToDataArray(source_buffer);
1767 }
1768
Reshape(int width,int height)1769 void WebGLRenderingContextBase::Reshape(int width, int height) {
1770 if (isContextLost())
1771 return;
1772
1773 GLint buffer = 0;
1774 if (IsWebGL2()) {
1775 // This query returns client side cached binding, so it's trivial.
1776 // If it changes in the future, such query is heavy and should be avoided.
1777 ContextGL()->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &buffer);
1778 if (buffer) {
1779 ContextGL()->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1780 }
1781 }
1782
1783 // This is an approximation because at WebGLRenderingContextBase level we
1784 // don't know if the underlying FBO uses textures or renderbuffers.
1785 GLint max_size = std::min(max_texture_size_, max_renderbuffer_size_);
1786 GLint max_width = std::min(max_size, max_viewport_dims_[0]);
1787 GLint max_height = std::min(max_size, max_viewport_dims_[1]);
1788 width = Clamp(width, 1, max_width);
1789 height = Clamp(height, 1, max_height);
1790
1791 // Limit drawing buffer area to the resolution of an 8K monitor to avoid
1792 // memory exhaustion. Width or height may be larger than that size as long as
1793 // it's within the max viewport dimensions and total area remains within the
1794 // limit. For example: 7680x4320 should be fine.
1795 const int kMaxArea = 5760 * 5760;
1796 int current_area = width * height;
1797 if (current_area > kMaxArea) {
1798 // If we've exceeded the area limit scale the buffer down, preserving
1799 // ascpect ratio, until it fits.
1800 float scale_factor =
1801 sqrtf(static_cast<float>(kMaxArea) / static_cast<float>(current_area));
1802 width = std::max(1, static_cast<int>(width * scale_factor));
1803 height = std::max(1, static_cast<int>(height * scale_factor));
1804 }
1805
1806 // We don't have to mark the canvas as dirty, since the newly created image
1807 // buffer will also start off clear (and this matches what reshape will do).
1808 GetDrawingBuffer()->Resize(IntSize(width, height));
1809
1810 if (buffer) {
1811 ContextGL()->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
1812 static_cast<GLuint>(buffer));
1813 }
1814 }
1815
drawingBufferWidth() const1816 int WebGLRenderingContextBase::drawingBufferWidth() const {
1817 return isContextLost() ? 0 : GetDrawingBuffer()->Size().Width();
1818 }
1819
drawingBufferHeight() const1820 int WebGLRenderingContextBase::drawingBufferHeight() const {
1821 return isContextLost() ? 0 : GetDrawingBuffer()->Size().Height();
1822 }
1823
activeTexture(GLenum texture)1824 void WebGLRenderingContextBase::activeTexture(GLenum texture) {
1825 if (isContextLost())
1826 return;
1827 if (texture - GL_TEXTURE0 >= texture_units_.size()) {
1828 SynthesizeGLError(GL_INVALID_ENUM, "activeTexture",
1829 "texture unit out of range");
1830 return;
1831 }
1832 active_texture_unit_ = texture - GL_TEXTURE0;
1833 ContextGL()->ActiveTexture(texture);
1834 }
1835
attachShader(WebGLProgram * program,WebGLShader * shader)1836 void WebGLRenderingContextBase::attachShader(WebGLProgram* program,
1837 WebGLShader* shader) {
1838 if (!ValidateWebGLProgramOrShader("attachShader", program) ||
1839 !ValidateWebGLProgramOrShader("attachShader", shader))
1840 return;
1841 if (!program->AttachShader(shader)) {
1842 SynthesizeGLError(GL_INVALID_OPERATION, "attachShader",
1843 "shader attachment already has shader");
1844 return;
1845 }
1846 ContextGL()->AttachShader(ObjectOrZero(program), ObjectOrZero(shader));
1847 shader->OnAttached();
1848 }
1849
bindAttribLocation(WebGLProgram * program,GLuint index,const String & name)1850 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program,
1851 GLuint index,
1852 const String& name) {
1853 if (!ValidateWebGLProgramOrShader("bindAttribLocation", program))
1854 return;
1855 if (!ValidateLocationLength("bindAttribLocation", name))
1856 return;
1857 if (IsPrefixReserved(name)) {
1858 SynthesizeGLError(GL_INVALID_OPERATION, "bindAttribLocation",
1859 "reserved prefix");
1860 return;
1861 }
1862 ContextGL()->BindAttribLocation(ObjectOrZero(program), index,
1863 name.Utf8().c_str());
1864 }
1865
ValidateAndUpdateBufferBindTarget(const char * function_name,GLenum target,WebGLBuffer * buffer)1866 bool WebGLRenderingContextBase::ValidateAndUpdateBufferBindTarget(
1867 const char* function_name,
1868 GLenum target,
1869 WebGLBuffer* buffer) {
1870 if (!ValidateBufferTarget(function_name, target))
1871 return false;
1872
1873 if (buffer && buffer->GetInitialTarget() &&
1874 buffer->GetInitialTarget() != target) {
1875 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
1876 "buffers can not be used with multiple targets");
1877 return false;
1878 }
1879
1880 switch (target) {
1881 case GL_ARRAY_BUFFER:
1882 bound_array_buffer_ = buffer;
1883 break;
1884 case GL_ELEMENT_ARRAY_BUFFER:
1885 bound_vertex_array_object_->SetElementArrayBuffer(buffer);
1886 break;
1887 default:
1888 NOTREACHED();
1889 return false;
1890 }
1891
1892 if (buffer && !buffer->GetInitialTarget())
1893 buffer->SetInitialTarget(target);
1894 return true;
1895 }
1896
bindBuffer(GLenum target,WebGLBuffer * buffer)1897 void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) {
1898 if (!ValidateNullableWebGLObject("bindBuffer", buffer))
1899 return;
1900 if (!ValidateAndUpdateBufferBindTarget("bindBuffer", target, buffer))
1901 return;
1902 ContextGL()->BindBuffer(target, ObjectOrZero(buffer));
1903 }
1904
bindFramebuffer(GLenum target,WebGLFramebuffer * buffer)1905 void WebGLRenderingContextBase::bindFramebuffer(GLenum target,
1906 WebGLFramebuffer* buffer) {
1907 if (!ValidateNullableWebGLObject("bindFramebuffer", buffer))
1908 return;
1909
1910 if (target != GL_FRAMEBUFFER) {
1911 SynthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target");
1912 return;
1913 }
1914
1915 SetFramebuffer(target, buffer);
1916 }
1917
bindRenderbuffer(GLenum target,WebGLRenderbuffer * render_buffer)1918 void WebGLRenderingContextBase::bindRenderbuffer(
1919 GLenum target,
1920 WebGLRenderbuffer* render_buffer) {
1921 if (!ValidateNullableWebGLObject("bindRenderbuffer", render_buffer))
1922 return;
1923 if (target != GL_RENDERBUFFER) {
1924 SynthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target");
1925 return;
1926 }
1927 renderbuffer_binding_ = render_buffer;
1928 ContextGL()->BindRenderbuffer(target, ObjectOrZero(render_buffer));
1929 if (render_buffer)
1930 render_buffer->SetHasEverBeenBound();
1931 }
1932
bindTexture(GLenum target,WebGLTexture * texture)1933 void WebGLRenderingContextBase::bindTexture(GLenum target,
1934 WebGLTexture* texture) {
1935 if (!ValidateNullableWebGLObject("bindTexture", texture))
1936 return;
1937 if (texture && texture->GetTarget() && texture->GetTarget() != target) {
1938 SynthesizeGLError(GL_INVALID_OPERATION, "bindTexture",
1939 "textures can not be used with multiple targets");
1940 return;
1941 }
1942
1943 if (target == GL_TEXTURE_2D) {
1944 texture_units_[active_texture_unit_].texture2d_binding_ = texture;
1945 } else if (target == GL_TEXTURE_CUBE_MAP) {
1946 texture_units_[active_texture_unit_].texture_cube_map_binding_ = texture;
1947 } else if (IsWebGL2() && target == GL_TEXTURE_2D_ARRAY) {
1948 texture_units_[active_texture_unit_].texture2d_array_binding_ = texture;
1949 } else if (IsWebGL2() && target == GL_TEXTURE_3D) {
1950 texture_units_[active_texture_unit_].texture3d_binding_ = texture;
1951 } else if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
1952 if (!ExtensionEnabled(kWebGLVideoTextureName)) {
1953 SynthesizeGLError(
1954 GL_INVALID_VALUE, "bindTexture",
1955 "unhandled type, WEBGL_video_texture extension not enabled");
1956 return;
1957 }
1958 texture_units_[active_texture_unit_].texture_video_image_binding_ = texture;
1959 } else {
1960 SynthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target");
1961 return;
1962 }
1963
1964 // We use TEXTURE_EXTERNAL_OES to implement video texture on Android platform
1965 if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
1966 #if defined(OS_ANDROID)
1967 // TODO(crbug.com/776222): Support extension on Android
1968 NOTIMPLEMENTED();
1969 return;
1970 #else
1971 // TODO(crbug.com/776222): Using GL_TEXTURE_VIDEO_IMAGE_WEBGL in blink
1972 ContextGL()->BindTexture(GL_TEXTURE_2D, ObjectOrZero(texture));
1973 if (texture && !texture->GetTarget()) {
1974 ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1975 GL_LINEAR);
1976 ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1977 GL_LINEAR);
1978 ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1979 GL_CLAMP_TO_EDGE);
1980 ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1981 GL_CLAMP_TO_EDGE);
1982 }
1983 #endif // defined OS_ANDROID
1984 } else {
1985 ContextGL()->BindTexture(target, ObjectOrZero(texture));
1986 }
1987 if (texture) {
1988 texture->SetTarget(target);
1989 one_plus_max_non_default_texture_unit_ =
1990 max(active_texture_unit_ + 1, one_plus_max_non_default_texture_unit_);
1991 } else {
1992 // If the disabled index is the current maximum, trace backwards to find the
1993 // new max enabled texture index
1994 if (one_plus_max_non_default_texture_unit_ == active_texture_unit_ + 1) {
1995 FindNewMaxNonDefaultTextureUnit();
1996 }
1997 }
1998
1999 // Note: previously we used to automatically set the TEXTURE_WRAP_R
2000 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
2001 // ES 2.0 doesn't expose this flag (a bug in the specification) and
2002 // otherwise the application has no control over the seams in this
2003 // dimension. However, it appears that supporting this properly on all
2004 // platforms is fairly involved (will require a HashMap from texture ID
2005 // in all ports), and we have not had any complaints, so the logic has
2006 // been removed.
2007 }
2008
blendColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)2009 void WebGLRenderingContextBase::blendColor(GLfloat red,
2010 GLfloat green,
2011 GLfloat blue,
2012 GLfloat alpha) {
2013 if (isContextLost())
2014 return;
2015 ContextGL()->BlendColor(red, green, blue, alpha);
2016 }
2017
blendEquation(GLenum mode)2018 void WebGLRenderingContextBase::blendEquation(GLenum mode) {
2019 if (isContextLost() || !ValidateBlendEquation("blendEquation", mode))
2020 return;
2021 ContextGL()->BlendEquation(mode);
2022 }
2023
blendEquationSeparate(GLenum mode_rgb,GLenum mode_alpha)2024 void WebGLRenderingContextBase::blendEquationSeparate(GLenum mode_rgb,
2025 GLenum mode_alpha) {
2026 if (isContextLost() ||
2027 !ValidateBlendEquation("blendEquationSeparate", mode_rgb) ||
2028 !ValidateBlendEquation("blendEquationSeparate", mode_alpha))
2029 return;
2030 ContextGL()->BlendEquationSeparate(mode_rgb, mode_alpha);
2031 }
2032
blendFunc(GLenum sfactor,GLenum dfactor)2033 void WebGLRenderingContextBase::blendFunc(GLenum sfactor, GLenum dfactor) {
2034 if (isContextLost() ||
2035 !ValidateBlendFuncFactors("blendFunc", sfactor, dfactor))
2036 return;
2037 ContextGL()->BlendFunc(sfactor, dfactor);
2038 }
2039
blendFuncSeparate(GLenum src_rgb,GLenum dst_rgb,GLenum src_alpha,GLenum dst_alpha)2040 void WebGLRenderingContextBase::blendFuncSeparate(GLenum src_rgb,
2041 GLenum dst_rgb,
2042 GLenum src_alpha,
2043 GLenum dst_alpha) {
2044 // Note: Alpha does not have the same restrictions as RGB.
2045 if (isContextLost() ||
2046 !ValidateBlendFuncFactors("blendFuncSeparate", src_rgb, dst_rgb))
2047 return;
2048 ContextGL()->BlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha);
2049 }
2050
BufferDataImpl(GLenum target,int64_t size,const void * data,GLenum usage)2051 void WebGLRenderingContextBase::BufferDataImpl(GLenum target,
2052 int64_t size,
2053 const void* data,
2054 GLenum usage) {
2055 WebGLBuffer* buffer = ValidateBufferDataTarget("bufferData", target);
2056 if (!buffer)
2057 return;
2058
2059 if (!ValidateBufferDataUsage("bufferData", usage))
2060 return;
2061
2062 if (!ValidateValueFitNonNegInt32("bufferData", "size", size))
2063 return;
2064
2065 buffer->SetSize(size);
2066
2067 ContextGL()->BufferData(target, static_cast<GLsizeiptr>(size), data, usage);
2068 }
2069
bufferData(GLenum target,int64_t size,GLenum usage)2070 void WebGLRenderingContextBase::bufferData(GLenum target,
2071 int64_t size,
2072 GLenum usage) {
2073 if (isContextLost())
2074 return;
2075 BufferDataImpl(target, size, nullptr, usage);
2076 }
2077
bufferData(GLenum target,DOMArrayBuffer * data,GLenum usage)2078 void WebGLRenderingContextBase::bufferData(GLenum target,
2079 DOMArrayBuffer* data,
2080 GLenum usage) {
2081 if (isContextLost())
2082 return;
2083 if (!data) {
2084 SynthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data");
2085 return;
2086 }
2087 BufferDataImpl(target, data->ByteLength(), data->Data(), usage);
2088 }
2089
bufferData(GLenum target,MaybeShared<DOMArrayBufferView> data,GLenum usage)2090 void WebGLRenderingContextBase::bufferData(GLenum target,
2091 MaybeShared<DOMArrayBufferView> data,
2092 GLenum usage) {
2093 if (isContextLost())
2094 return;
2095 DCHECK(data);
2096 BufferDataImpl(target, data.View()->byteLength(),
2097 data.View()->BaseAddressMaybeShared(), usage);
2098 }
2099
BufferSubDataImpl(GLenum target,int64_t offset,GLsizeiptr size,const void * data)2100 void WebGLRenderingContextBase::BufferSubDataImpl(GLenum target,
2101 int64_t offset,
2102 GLsizeiptr size,
2103 const void* data) {
2104 WebGLBuffer* buffer = ValidateBufferDataTarget("bufferSubData", target);
2105 if (!buffer)
2106 return;
2107 if (!ValidateValueFitNonNegInt32("bufferSubData", "offset", offset))
2108 return;
2109 if (!data)
2110 return;
2111 if (offset + static_cast<int64_t>(size) > buffer->GetSize()) {
2112 SynthesizeGLError(GL_INVALID_VALUE, "bufferSubData", "buffer overflow");
2113 return;
2114 }
2115
2116 ContextGL()->BufferSubData(target, static_cast<GLintptr>(offset), size, data);
2117 }
2118
bufferSubData(GLenum target,int64_t offset,DOMArrayBuffer * data)2119 void WebGLRenderingContextBase::bufferSubData(GLenum target,
2120 int64_t offset,
2121 DOMArrayBuffer* data) {
2122 if (isContextLost())
2123 return;
2124 DCHECK(data);
2125 BufferSubDataImpl(target, offset, data->ByteLength(), data->Data());
2126 }
2127
bufferSubData(GLenum target,int64_t offset,const FlexibleArrayBufferView & data)2128 void WebGLRenderingContextBase::bufferSubData(
2129 GLenum target,
2130 int64_t offset,
2131 const FlexibleArrayBufferView& data) {
2132 if (isContextLost())
2133 return;
2134 DCHECK(!data.IsNull());
2135 BufferSubDataImpl(target, offset, data.ByteLength(),
2136 data.BaseAddressMaybeOnStack());
2137 }
2138
ValidateFramebufferTarget(GLenum target)2139 bool WebGLRenderingContextBase::ValidateFramebufferTarget(GLenum target) {
2140 if (target == GL_FRAMEBUFFER)
2141 return true;
2142 return false;
2143 }
2144
GetFramebufferBinding(GLenum target)2145 WebGLFramebuffer* WebGLRenderingContextBase::GetFramebufferBinding(
2146 GLenum target) {
2147 if (target == GL_FRAMEBUFFER)
2148 return framebuffer_binding_.Get();
2149 return nullptr;
2150 }
2151
GetReadFramebufferBinding()2152 WebGLFramebuffer* WebGLRenderingContextBase::GetReadFramebufferBinding() {
2153 return framebuffer_binding_.Get();
2154 }
2155
checkFramebufferStatus(GLenum target)2156 GLenum WebGLRenderingContextBase::checkFramebufferStatus(GLenum target) {
2157 if (isContextLost())
2158 return GL_FRAMEBUFFER_UNSUPPORTED;
2159 if (!ValidateFramebufferTarget(target)) {
2160 SynthesizeGLError(GL_INVALID_ENUM, "checkFramebufferStatus",
2161 "invalid target");
2162 return 0;
2163 }
2164 WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
2165 if (framebuffer_binding) {
2166 const char* reason = "framebuffer incomplete";
2167 GLenum status = framebuffer_binding->CheckDepthStencilStatus(&reason);
2168 if (status != GL_FRAMEBUFFER_COMPLETE) {
2169 EmitGLWarning("checkFramebufferStatus", reason);
2170 return status;
2171 }
2172 }
2173 return ContextGL()->CheckFramebufferStatus(target);
2174 }
2175
clear(GLbitfield mask)2176 void WebGLRenderingContextBase::clear(GLbitfield mask) {
2177 if (isContextLost())
2178 return;
2179 if (mask &
2180 ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
2181 SynthesizeGLError(GL_INVALID_VALUE, "clear", "invalid mask");
2182 return;
2183 }
2184 const char* reason = "framebuffer incomplete";
2185 if (framebuffer_binding_ && framebuffer_binding_->CheckDepthStencilStatus(
2186 &reason) != GL_FRAMEBUFFER_COMPLETE) {
2187 SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
2188 return;
2189 }
2190
2191 if (!mask) {
2192 // Use OnErrorMessage because it's both rate-limited and obeys the
2193 // webGLErrorsToConsole setting.
2194 OnErrorMessage(
2195 "Performance warning: clear() called with no buffers in bitmask", 0);
2196 // Don't skip the call to ClearIfComposited below; it has side
2197 // effects even without the user requesting to clear any buffers.
2198 }
2199
2200 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2201 drawing_buffer_.get());
2202
2203 if (ClearIfComposited(mask) != kCombinedClear) {
2204 // If clearing the default back buffer's depth buffer, also clear the
2205 // stencil buffer, if one was allocated implicitly. This avoids performance
2206 // problems on some GPUs.
2207 if (!framebuffer_binding_ &&
2208 GetDrawingBuffer()->HasImplicitStencilBuffer() &&
2209 (mask & GL_DEPTH_BUFFER_BIT)) {
2210 // It shouldn't matter what value it's cleared to, since in other queries
2211 // in the API, we claim that the stencil buffer doesn't exist.
2212 mask |= GL_STENCIL_BUFFER_BIT;
2213 }
2214 ContextGL()->Clear(mask);
2215 }
2216 MarkContextChanged(kCanvasChanged);
2217 }
2218
clearColor(GLfloat r,GLfloat g,GLfloat b,GLfloat a)2219 void WebGLRenderingContextBase::clearColor(GLfloat r,
2220 GLfloat g,
2221 GLfloat b,
2222 GLfloat a) {
2223 if (isContextLost())
2224 return;
2225 if (std::isnan(r))
2226 r = 0;
2227 if (std::isnan(g))
2228 g = 0;
2229 if (std::isnan(b))
2230 b = 0;
2231 if (std::isnan(a))
2232 a = 1;
2233 clear_color_[0] = r;
2234 clear_color_[1] = g;
2235 clear_color_[2] = b;
2236 clear_color_[3] = a;
2237 ContextGL()->ClearColor(r, g, b, a);
2238 }
2239
clearDepth(GLfloat depth)2240 void WebGLRenderingContextBase::clearDepth(GLfloat depth) {
2241 if (isContextLost())
2242 return;
2243 clear_depth_ = depth;
2244 ContextGL()->ClearDepthf(depth);
2245 }
2246
clearStencil(GLint s)2247 void WebGLRenderingContextBase::clearStencil(GLint s) {
2248 if (isContextLost())
2249 return;
2250 clear_stencil_ = s;
2251 ContextGL()->ClearStencil(s);
2252 }
2253
colorMask(GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha)2254 void WebGLRenderingContextBase::colorMask(GLboolean red,
2255 GLboolean green,
2256 GLboolean blue,
2257 GLboolean alpha) {
2258 if (isContextLost())
2259 return;
2260 color_mask_[0] = red;
2261 color_mask_[1] = green;
2262 color_mask_[2] = blue;
2263 color_mask_[3] = alpha;
2264 ContextGL()->ColorMask(red, green, blue, alpha);
2265 }
2266
compileShader(WebGLShader * shader)2267 void WebGLRenderingContextBase::compileShader(WebGLShader* shader) {
2268 if (!ValidateWebGLProgramOrShader("compileShader", shader))
2269 return;
2270 ContextGL()->CompileShader(ObjectOrZero(shader));
2271 }
2272
compressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,MaybeShared<DOMArrayBufferView> data)2273 void WebGLRenderingContextBase::compressedTexImage2D(
2274 GLenum target,
2275 GLint level,
2276 GLenum internalformat,
2277 GLsizei width,
2278 GLsizei height,
2279 GLint border,
2280 MaybeShared<DOMArrayBufferView> data) {
2281 if (isContextLost())
2282 return;
2283 if (!ValidateTexture2DBinding("compressedTexImage2D", target))
2284 return;
2285 if (!ValidateCompressedTexFormat("compressedTexImage2D", internalformat))
2286 return;
2287 GLsizei data_length;
2288 if (!ExtractDataLengthIfValid("compressedTexImage2D", data, &data_length))
2289 return;
2290 ContextGL()->CompressedTexImage2D(target, level, internalformat, width,
2291 height, border, data_length,
2292 data.View()->BaseAddressMaybeShared());
2293 }
2294
compressedTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,MaybeShared<DOMArrayBufferView> data)2295 void WebGLRenderingContextBase::compressedTexSubImage2D(
2296 GLenum target,
2297 GLint level,
2298 GLint xoffset,
2299 GLint yoffset,
2300 GLsizei width,
2301 GLsizei height,
2302 GLenum format,
2303 MaybeShared<DOMArrayBufferView> data) {
2304 if (isContextLost())
2305 return;
2306 if (!ValidateTexture2DBinding("compressedTexSubImage2D", target))
2307 return;
2308 if (!ValidateCompressedTexFormat("compressedTexSubImage2D", format))
2309 return;
2310 GLsizei data_length;
2311 if (!ExtractDataLengthIfValid("compressedTexSubImage2D", data, &data_length))
2312 return;
2313 ContextGL()->CompressedTexSubImage2D(target, level, xoffset, yoffset, width,
2314 height, format, data_length,
2315 data.View()->BaseAddressMaybeShared());
2316 }
2317
ValidateSettableTexFormat(const char * function_name,GLenum format)2318 bool WebGLRenderingContextBase::ValidateSettableTexFormat(
2319 const char* function_name,
2320 GLenum format) {
2321 if (IsWebGL2())
2322 return true;
2323
2324 if (WebGLImageConversion::GetChannelBitsByFormat(format) &
2325 WebGLImageConversion::kChannelDepthStencil) {
2326 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2327 "format can not be set, only rendered to");
2328 return false;
2329 }
2330 return true;
2331 }
2332
ValidateCopyTexFormat(const char * function_name,GLenum internalformat)2333 bool WebGLRenderingContextBase::ValidateCopyTexFormat(const char* function_name,
2334 GLenum internalformat) {
2335 if (!is_web_gl2_internal_formats_copy_tex_image_added_ && IsWebGL2()) {
2336 ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
2337 kSupportedInternalFormatsES3);
2338 is_web_gl2_internal_formats_copy_tex_image_added_ = true;
2339 }
2340 if (!is_ext_color_buffer_float_formats_added_ &&
2341 ExtensionEnabled(kEXTColorBufferFloatName)) {
2342 ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
2343 kSupportedInternalFormatsCopyTexImageFloatES3);
2344 is_ext_color_buffer_float_formats_added_ = true;
2345 }
2346 if (!is_ext_color_buffer_half_float_formats_added_ &&
2347 ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
2348 ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
2349 kSupportedInternalFormatsCopyTexImageHalfFloatES3);
2350 is_ext_color_buffer_half_float_formats_added_ = true;
2351 }
2352
2353 if (supported_internal_formats_copy_tex_image_.find(internalformat) ==
2354 supported_internal_formats_copy_tex_image_.end()) {
2355 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid internalformat");
2356 return false;
2357 }
2358
2359 return true;
2360 }
2361
copyTexImage2D(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,GLint border)2362 void WebGLRenderingContextBase::copyTexImage2D(GLenum target,
2363 GLint level,
2364 GLenum internalformat,
2365 GLint x,
2366 GLint y,
2367 GLsizei width,
2368 GLsizei height,
2369 GLint border) {
2370 if (isContextLost())
2371 return;
2372 if (!ValidateTexture2DBinding("copyTexImage2D", target))
2373 return;
2374 if (!ValidateCopyTexFormat("copyTexImage2D", internalformat))
2375 return;
2376 if (!ValidateSettableTexFormat("copyTexImage2D", internalformat))
2377 return;
2378 WebGLFramebuffer* read_framebuffer_binding = nullptr;
2379 if (!ValidateReadBufferAndGetInfo("copyTexImage2D", read_framebuffer_binding))
2380 return;
2381 ClearIfComposited();
2382 ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
2383 read_framebuffer_binding);
2384 ContextGL()->CopyTexImage2D(target, level, internalformat, x, y, width,
2385 height, border);
2386 }
2387
copyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height)2388 void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target,
2389 GLint level,
2390 GLint xoffset,
2391 GLint yoffset,
2392 GLint x,
2393 GLint y,
2394 GLsizei width,
2395 GLsizei height) {
2396 if (isContextLost())
2397 return;
2398 if (!ValidateTexture2DBinding("copyTexSubImage2D", target))
2399 return;
2400 WebGLFramebuffer* read_framebuffer_binding = nullptr;
2401 if (!ValidateReadBufferAndGetInfo("copyTexSubImage2D",
2402 read_framebuffer_binding))
2403 return;
2404 ClearIfComposited();
2405 ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
2406 read_framebuffer_binding);
2407 ContextGL()->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width,
2408 height);
2409 }
2410
createBuffer()2411 WebGLBuffer* WebGLRenderingContextBase::createBuffer() {
2412 if (isContextLost())
2413 return nullptr;
2414 return MakeGarbageCollected<WebGLBuffer>(this);
2415 }
2416
createFramebuffer()2417 WebGLFramebuffer* WebGLRenderingContextBase::createFramebuffer() {
2418 if (isContextLost())
2419 return nullptr;
2420 return MakeGarbageCollected<WebGLFramebuffer>(this);
2421 }
2422
createTexture()2423 WebGLTexture* WebGLRenderingContextBase::createTexture() {
2424 if (isContextLost())
2425 return nullptr;
2426 return MakeGarbageCollected<WebGLTexture>(this);
2427 }
2428
createProgram()2429 WebGLProgram* WebGLRenderingContextBase::createProgram() {
2430 if (isContextLost())
2431 return nullptr;
2432 return MakeGarbageCollected<WebGLProgram>(this);
2433 }
2434
createRenderbuffer()2435 WebGLRenderbuffer* WebGLRenderingContextBase::createRenderbuffer() {
2436 if (isContextLost())
2437 return nullptr;
2438 return MakeGarbageCollected<WebGLRenderbuffer>(this);
2439 }
2440
SetBoundVertexArrayObject(WebGLVertexArrayObjectBase * array_object)2441 void WebGLRenderingContextBase::SetBoundVertexArrayObject(
2442 WebGLVertexArrayObjectBase* array_object) {
2443 if (array_object)
2444 bound_vertex_array_object_ = array_object;
2445 else
2446 bound_vertex_array_object_ = default_vertex_array_object_;
2447 }
2448
createShader(GLenum type)2449 WebGLShader* WebGLRenderingContextBase::createShader(GLenum type) {
2450 if (isContextLost())
2451 return nullptr;
2452 if (!ValidateShaderType("createShader", type)) {
2453 return nullptr;
2454 }
2455
2456 return MakeGarbageCollected<WebGLShader>(this, type);
2457 }
2458
cullFace(GLenum mode)2459 void WebGLRenderingContextBase::cullFace(GLenum mode) {
2460 if (isContextLost())
2461 return;
2462 ContextGL()->CullFace(mode);
2463 }
2464
DeleteObject(WebGLObject * object)2465 bool WebGLRenderingContextBase::DeleteObject(WebGLObject* object) {
2466 if (isContextLost() || !object)
2467 return false;
2468 if (!object->Validate(ContextGroup(), this)) {
2469 SynthesizeGLError(GL_INVALID_OPERATION, "delete",
2470 "object does not belong to this context");
2471 return false;
2472 }
2473 if (object->MarkedForDeletion()) {
2474 // This is specified to be a no-op, including skipping all unbinding from
2475 // the context's attachment points that would otherwise happen.
2476 return false;
2477 }
2478 if (object->HasObject()) {
2479 // We need to pass in context here because we want
2480 // things in this context unbound.
2481 object->DeleteObject(ContextGL());
2482 }
2483 return true;
2484 }
2485
deleteBuffer(WebGLBuffer * buffer)2486 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer) {
2487 if (!DeleteObject(buffer))
2488 return;
2489 RemoveBoundBuffer(buffer);
2490 }
2491
deleteFramebuffer(WebGLFramebuffer * framebuffer)2492 void WebGLRenderingContextBase::deleteFramebuffer(
2493 WebGLFramebuffer* framebuffer) {
2494 // Don't allow the application to delete an opaque framebuffer.
2495 if (framebuffer && framebuffer->Opaque()) {
2496 SynthesizeGLError(GL_INVALID_OPERATION, "deleteFramebuffer",
2497 "cannot delete an opaque framebuffer");
2498 return;
2499 }
2500 if (!DeleteObject(framebuffer))
2501 return;
2502 if (framebuffer == framebuffer_binding_) {
2503 framebuffer_binding_ = nullptr;
2504 // Have to call drawingBuffer()->bind() here to bind back to internal fbo.
2505 GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
2506 }
2507 }
2508
deleteProgram(WebGLProgram * program)2509 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program) {
2510 DeleteObject(program);
2511 // We don't reset m_currentProgram to 0 here because the deletion of the
2512 // current program is delayed.
2513 }
2514
deleteRenderbuffer(WebGLRenderbuffer * renderbuffer)2515 void WebGLRenderingContextBase::deleteRenderbuffer(
2516 WebGLRenderbuffer* renderbuffer) {
2517 if (!DeleteObject(renderbuffer))
2518 return;
2519 if (renderbuffer == renderbuffer_binding_) {
2520 renderbuffer_binding_ = nullptr;
2521 }
2522 if (framebuffer_binding_)
2523 framebuffer_binding_->RemoveAttachmentFromBoundFramebuffer(GL_FRAMEBUFFER,
2524 renderbuffer);
2525 if (GetFramebufferBinding(GL_READ_FRAMEBUFFER))
2526 GetFramebufferBinding(GL_READ_FRAMEBUFFER)
2527 ->RemoveAttachmentFromBoundFramebuffer(GL_READ_FRAMEBUFFER,
2528 renderbuffer);
2529 }
2530
deleteShader(WebGLShader * shader)2531 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader) {
2532 DeleteObject(shader);
2533 }
2534
deleteTexture(WebGLTexture * texture)2535 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture) {
2536 if (!DeleteObject(texture))
2537 return;
2538
2539 int max_bound_texture_index = -1;
2540 for (wtf_size_t i = 0; i < one_plus_max_non_default_texture_unit_; ++i) {
2541 if (texture == texture_units_[i].texture2d_binding_) {
2542 texture_units_[i].texture2d_binding_ = nullptr;
2543 max_bound_texture_index = i;
2544 }
2545 if (texture == texture_units_[i].texture_cube_map_binding_) {
2546 texture_units_[i].texture_cube_map_binding_ = nullptr;
2547 max_bound_texture_index = i;
2548 }
2549 if (IsWebGL2()) {
2550 if (texture == texture_units_[i].texture3d_binding_) {
2551 texture_units_[i].texture3d_binding_ = nullptr;
2552 max_bound_texture_index = i;
2553 }
2554 if (texture == texture_units_[i].texture2d_array_binding_) {
2555 texture_units_[i].texture2d_array_binding_ = nullptr;
2556 max_bound_texture_index = i;
2557 }
2558 }
2559 }
2560 if (framebuffer_binding_)
2561 framebuffer_binding_->RemoveAttachmentFromBoundFramebuffer(GL_FRAMEBUFFER,
2562 texture);
2563 if (GetFramebufferBinding(GL_READ_FRAMEBUFFER))
2564 GetFramebufferBinding(GL_READ_FRAMEBUFFER)
2565 ->RemoveAttachmentFromBoundFramebuffer(GL_READ_FRAMEBUFFER, texture);
2566
2567 // If the deleted was bound to the the current maximum index, trace backwards
2568 // to find the new max texture index.
2569 if (one_plus_max_non_default_texture_unit_ ==
2570 static_cast<wtf_size_t>(max_bound_texture_index + 1)) {
2571 FindNewMaxNonDefaultTextureUnit();
2572 }
2573 }
2574
depthFunc(GLenum func)2575 void WebGLRenderingContextBase::depthFunc(GLenum func) {
2576 if (isContextLost())
2577 return;
2578 ContextGL()->DepthFunc(func);
2579 }
2580
depthMask(GLboolean flag)2581 void WebGLRenderingContextBase::depthMask(GLboolean flag) {
2582 if (isContextLost())
2583 return;
2584 depth_mask_ = flag;
2585 ContextGL()->DepthMask(flag);
2586 }
2587
depthRange(GLfloat z_near,GLfloat z_far)2588 void WebGLRenderingContextBase::depthRange(GLfloat z_near, GLfloat z_far) {
2589 if (isContextLost())
2590 return;
2591 // Check required by WebGL spec section 6.12
2592 if (z_near > z_far) {
2593 SynthesizeGLError(GL_INVALID_OPERATION, "depthRange", "zNear > zFar");
2594 return;
2595 }
2596 ContextGL()->DepthRangef(z_near, z_far);
2597 }
2598
detachShader(WebGLProgram * program,WebGLShader * shader)2599 void WebGLRenderingContextBase::detachShader(WebGLProgram* program,
2600 WebGLShader* shader) {
2601 if (!ValidateWebGLProgramOrShader("detachShader", program) ||
2602 !ValidateWebGLProgramOrShader("detachShader", shader))
2603 return;
2604 if (!program->DetachShader(shader)) {
2605 SynthesizeGLError(GL_INVALID_OPERATION, "detachShader",
2606 "shader not attached");
2607 return;
2608 }
2609 ContextGL()->DetachShader(ObjectOrZero(program), ObjectOrZero(shader));
2610 shader->OnDetached(ContextGL());
2611 }
2612
disable(GLenum cap)2613 void WebGLRenderingContextBase::disable(GLenum cap) {
2614 if (isContextLost() || !ValidateCapability("disable", cap))
2615 return;
2616 if (cap == GL_STENCIL_TEST) {
2617 stencil_enabled_ = false;
2618 ApplyStencilTest();
2619 return;
2620 }
2621 if (cap == GL_SCISSOR_TEST)
2622 scissor_enabled_ = false;
2623 ContextGL()->Disable(cap);
2624 }
2625
disableVertexAttribArray(GLuint index)2626 void WebGLRenderingContextBase::disableVertexAttribArray(GLuint index) {
2627 if (isContextLost())
2628 return;
2629 if (index >= max_vertex_attribs_) {
2630 SynthesizeGLError(GL_INVALID_VALUE, "disableVertexAttribArray",
2631 "index out of range");
2632 return;
2633 }
2634
2635 bound_vertex_array_object_->SetAttribEnabled(index, false);
2636 ContextGL()->DisableVertexAttribArray(index);
2637 }
2638
ValidateRenderingState(const char * function_name)2639 bool WebGLRenderingContextBase::ValidateRenderingState(
2640 const char* function_name) {
2641 // Command buffer will not error if no program is bound.
2642 if (!current_program_) {
2643 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2644 "no valid shader program in use");
2645 return false;
2646 }
2647
2648 return true;
2649 }
2650
ValidateNullableWebGLObject(const char * function_name,WebGLObject * object)2651 bool WebGLRenderingContextBase::ValidateNullableWebGLObject(
2652 const char* function_name,
2653 WebGLObject* object) {
2654 if (isContextLost())
2655 return false;
2656 if (!object) {
2657 // This differs in behavior to ValidateWebGLObject; null objects are allowed
2658 // in these entry points.
2659 return true;
2660 }
2661 return ValidateWebGLObject(function_name, object);
2662 }
2663
ValidateWebGLObject(const char * function_name,WebGLObject * object)2664 bool WebGLRenderingContextBase::ValidateWebGLObject(const char* function_name,
2665 WebGLObject* object) {
2666 if (isContextLost())
2667 return false;
2668 DCHECK(object);
2669 if (object->MarkedForDeletion()) {
2670 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2671 "attempt to use a deleted object");
2672 return false;
2673 }
2674 if (!object->Validate(ContextGroup(), this)) {
2675 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2676 "object does not belong to this context");
2677 return false;
2678 }
2679 return true;
2680 }
2681
ValidateWebGLProgramOrShader(const char * function_name,WebGLObject * object)2682 bool WebGLRenderingContextBase::ValidateWebGLProgramOrShader(
2683 const char* function_name,
2684 WebGLObject* object) {
2685 if (isContextLost())
2686 return false;
2687 DCHECK(object);
2688 // OpenGL ES 3.0.5 p. 45:
2689 // "Commands that accept shader or program object names will generate the
2690 // error INVALID_VALUE if the provided name is not the name of either a shader
2691 // or program object and INVALID_OPERATION if the provided name identifies an
2692 // object that is not the expected type."
2693 //
2694 // Programs and shaders also have slightly different lifetime rules than other
2695 // objects in the API; they continue to be usable after being marked for
2696 // deletion.
2697 if (!object->HasObject()) {
2698 SynthesizeGLError(GL_INVALID_VALUE, function_name,
2699 "attempt to use a deleted object");
2700 return false;
2701 }
2702 if (!object->Validate(ContextGroup(), this)) {
2703 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2704 "object does not belong to this context");
2705 return false;
2706 }
2707 return true;
2708 }
2709
drawArraysImpl(GLenum mode,GLint first,GLsizei count)2710 void WebGLRenderingContextBase::drawArraysImpl(GLenum mode,
2711 GLint first,
2712 GLsizei count) {
2713 if (!ValidateDrawArrays("drawArrays"))
2714 return;
2715
2716 if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2717 SynthesizeGLError(GL_INVALID_OPERATION, "drawArrays",
2718 "no buffer is bound to enabled attribute");
2719 return;
2720 }
2721
2722 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2723 drawing_buffer_.get());
2724 OnBeforeDrawCall();
2725 ContextGL()->DrawArrays(mode, first, count);
2726 }
2727
drawElementsImpl(GLenum mode,GLsizei count,GLenum type,int64_t offset)2728 void WebGLRenderingContextBase::drawElementsImpl(GLenum mode,
2729 GLsizei count,
2730 GLenum type,
2731 int64_t offset) {
2732 if (!ValidateDrawElements("drawElements", type, offset))
2733 return;
2734
2735 if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2736 SynthesizeGLError(GL_INVALID_OPERATION, "drawElements",
2737 "no buffer is bound to enabled attribute");
2738 return;
2739 }
2740
2741 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2742 drawing_buffer_.get());
2743 OnBeforeDrawCall();
2744 ContextGL()->DrawElements(
2745 mode, count, type,
2746 reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
2747 }
2748
DrawArraysInstancedANGLE(GLenum mode,GLint first,GLsizei count,GLsizei primcount)2749 void WebGLRenderingContextBase::DrawArraysInstancedANGLE(GLenum mode,
2750 GLint first,
2751 GLsizei count,
2752 GLsizei primcount) {
2753 if (!ValidateDrawArrays("drawArraysInstancedANGLE"))
2754 return;
2755
2756 if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2757 SynthesizeGLError(GL_INVALID_OPERATION, "drawArraysInstancedANGLE",
2758 "no buffer is bound to enabled attribute");
2759 return;
2760 }
2761
2762 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2763 drawing_buffer_.get());
2764 OnBeforeDrawCall();
2765 ContextGL()->DrawArraysInstancedANGLE(mode, first, count, primcount);
2766 }
2767
DrawElementsInstancedANGLE(GLenum mode,GLsizei count,GLenum type,int64_t offset,GLsizei primcount)2768 void WebGLRenderingContextBase::DrawElementsInstancedANGLE(GLenum mode,
2769 GLsizei count,
2770 GLenum type,
2771 int64_t offset,
2772 GLsizei primcount) {
2773 if (!ValidateDrawElements("drawElementsInstancedANGLE", type, offset))
2774 return;
2775
2776 if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2777 SynthesizeGLError(GL_INVALID_OPERATION, "drawElementsInstancedANGLE",
2778 "no buffer is bound to enabled attribute");
2779 return;
2780 }
2781
2782 ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2783 drawing_buffer_.get());
2784 OnBeforeDrawCall();
2785 ContextGL()->DrawElementsInstancedANGLE(
2786 mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)),
2787 primcount);
2788 }
2789
enable(GLenum cap)2790 void WebGLRenderingContextBase::enable(GLenum cap) {
2791 if (isContextLost() || !ValidateCapability("enable", cap))
2792 return;
2793 if (cap == GL_STENCIL_TEST) {
2794 stencil_enabled_ = true;
2795 ApplyStencilTest();
2796 return;
2797 }
2798 if (cap == GL_SCISSOR_TEST)
2799 scissor_enabled_ = true;
2800 ContextGL()->Enable(cap);
2801 }
2802
enableVertexAttribArray(GLuint index)2803 void WebGLRenderingContextBase::enableVertexAttribArray(GLuint index) {
2804 if (isContextLost())
2805 return;
2806 if (index >= max_vertex_attribs_) {
2807 SynthesizeGLError(GL_INVALID_VALUE, "enableVertexAttribArray",
2808 "index out of range");
2809 return;
2810 }
2811
2812 bound_vertex_array_object_->SetAttribEnabled(index, true);
2813 ContextGL()->EnableVertexAttribArray(index);
2814 }
2815
finish()2816 void WebGLRenderingContextBase::finish() {
2817 if (isContextLost())
2818 return;
2819 ContextGL()->Flush(); // Intentionally a flush, not a finish.
2820 }
2821
flush()2822 void WebGLRenderingContextBase::flush() {
2823 if (isContextLost())
2824 return;
2825 ContextGL()->Flush();
2826 }
2827
framebufferRenderbuffer(GLenum target,GLenum attachment,GLenum renderbuffertarget,WebGLRenderbuffer * buffer)2828 void WebGLRenderingContextBase::framebufferRenderbuffer(
2829 GLenum target,
2830 GLenum attachment,
2831 GLenum renderbuffertarget,
2832 WebGLRenderbuffer* buffer) {
2833 if (isContextLost() || !ValidateFramebufferFuncParameters(
2834 "framebufferRenderbuffer", target, attachment))
2835 return;
2836 if (renderbuffertarget != GL_RENDERBUFFER) {
2837 SynthesizeGLError(GL_INVALID_ENUM, "framebufferRenderbuffer",
2838 "invalid target");
2839 return;
2840 }
2841 if (!ValidateNullableWebGLObject("framebufferRenderbuffer", buffer))
2842 return;
2843 if (buffer && (!buffer->HasEverBeenBound())) {
2844 SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
2845 "renderbuffer has never been bound");
2846 return;
2847 }
2848 // Don't allow the default framebuffer to be mutated; all current
2849 // implementations use an FBO internally in place of the default
2850 // FBO.
2851 WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
2852 if (!framebuffer_binding || !framebuffer_binding->Object()) {
2853 SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
2854 "no framebuffer bound");
2855 return;
2856 }
2857 // Don't allow modifications to opaque framebuffer attachements.
2858 if (framebuffer_binding && framebuffer_binding->Opaque()) {
2859 SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
2860 "opaque framebuffer bound");
2861 return;
2862 }
2863 framebuffer_binding->SetAttachmentForBoundFramebuffer(target, attachment,
2864 buffer);
2865 ApplyStencilTest();
2866 }
2867
framebufferTexture2D(GLenum target,GLenum attachment,GLenum textarget,WebGLTexture * texture,GLint level)2868 void WebGLRenderingContextBase::framebufferTexture2D(GLenum target,
2869 GLenum attachment,
2870 GLenum textarget,
2871 WebGLTexture* texture,
2872 GLint level) {
2873 if (isContextLost() || !ValidateFramebufferFuncParameters(
2874 "framebufferTexture2D", target, attachment))
2875 return;
2876 if (!ValidateNullableWebGLObject("framebufferTexture2D", texture))
2877 return;
2878 // TODO(crbug.com/919711): validate texture's target against textarget.
2879
2880 // Don't allow the default framebuffer to be mutated; all current
2881 // implementations use an FBO internally in place of the default
2882 // FBO.
2883 WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
2884 if (!framebuffer_binding || !framebuffer_binding->Object()) {
2885 SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D",
2886 "no framebuffer bound");
2887 return;
2888 }
2889 // Don't allow modifications to opaque framebuffer attachements.
2890 if (framebuffer_binding && framebuffer_binding->Opaque()) {
2891 SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D",
2892 "opaque framebuffer bound");
2893 return;
2894 }
2895 framebuffer_binding->SetAttachmentForBoundFramebuffer(
2896 target, attachment, textarget, texture, level, 0, 0);
2897 ApplyStencilTest();
2898 }
2899
frontFace(GLenum mode)2900 void WebGLRenderingContextBase::frontFace(GLenum mode) {
2901 if (isContextLost())
2902 return;
2903 ContextGL()->FrontFace(mode);
2904 }
2905
generateMipmap(GLenum target)2906 void WebGLRenderingContextBase::generateMipmap(GLenum target) {
2907 if (isContextLost())
2908 return;
2909 if (!ValidateTextureBinding("generateMipmap", target))
2910 return;
2911 ContextGL()->GenerateMipmap(target);
2912 }
2913
getActiveAttrib(WebGLProgram * program,GLuint index)2914 WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib(
2915 WebGLProgram* program,
2916 GLuint index) {
2917 if (!ValidateWebGLProgramOrShader("getActiveAttrib", program))
2918 return nullptr;
2919 GLuint program_id = ObjectNonZero(program);
2920 GLint max_name_length = -1;
2921 ContextGL()->GetProgramiv(program_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
2922 &max_name_length);
2923 if (max_name_length < 0)
2924 return nullptr;
2925 if (max_name_length == 0) {
2926 SynthesizeGLError(GL_INVALID_VALUE, "getActiveAttrib",
2927 "no active attributes exist");
2928 return nullptr;
2929 }
2930 LChar* name_ptr;
2931 scoped_refptr<StringImpl> name_impl =
2932 StringImpl::CreateUninitialized(max_name_length, name_ptr);
2933 GLsizei length = 0;
2934 GLint size = -1;
2935 GLenum type = 0;
2936 ContextGL()->GetActiveAttrib(program_id, index, max_name_length, &length,
2937 &size, &type,
2938 reinterpret_cast<GLchar*>(name_ptr));
2939 if (size < 0)
2940 return nullptr;
2941 return MakeGarbageCollected<WebGLActiveInfo>(name_impl->Substring(0, length),
2942 type, size);
2943 }
2944
getActiveUniform(WebGLProgram * program,GLuint index)2945 WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform(
2946 WebGLProgram* program,
2947 GLuint index) {
2948 if (!ValidateWebGLProgramOrShader("getActiveUniform", program))
2949 return nullptr;
2950 GLuint program_id = ObjectNonZero(program);
2951 GLint max_name_length = -1;
2952 ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH,
2953 &max_name_length);
2954 if (max_name_length < 0)
2955 return nullptr;
2956 if (max_name_length == 0) {
2957 SynthesizeGLError(GL_INVALID_VALUE, "getActiveUniform",
2958 "no active uniforms exist");
2959 return nullptr;
2960 }
2961 LChar* name_ptr;
2962 scoped_refptr<StringImpl> name_impl =
2963 StringImpl::CreateUninitialized(max_name_length, name_ptr);
2964 GLsizei length = 0;
2965 GLint size = -1;
2966 GLenum type = 0;
2967 ContextGL()->GetActiveUniform(program_id, index, max_name_length, &length,
2968 &size, &type,
2969 reinterpret_cast<GLchar*>(name_ptr));
2970 if (size < 0)
2971 return nullptr;
2972 return MakeGarbageCollected<WebGLActiveInfo>(name_impl->Substring(0, length),
2973 type, size);
2974 }
2975
2976 base::Optional<HeapVector<Member<WebGLShader>>>
getAttachedShaders(WebGLProgram * program)2977 WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program) {
2978 if (!ValidateWebGLProgramOrShader("getAttachedShaders", program))
2979 return base::nullopt;
2980
2981 HeapVector<Member<WebGLShader>> shader_objects;
2982 for (GLenum shaderType : {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}) {
2983 WebGLShader* shader = program->GetAttachedShader(shaderType);
2984 if (shader)
2985 shader_objects.push_back(shader);
2986 }
2987 return shader_objects;
2988 }
2989
getAttribLocation(WebGLProgram * program,const String & name)2990 GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program,
2991 const String& name) {
2992 if (!ValidateWebGLProgramOrShader("getAttribLocation", program))
2993 return -1;
2994 if (!ValidateLocationLength("getAttribLocation", name))
2995 return -1;
2996 if (!ValidateString("getAttribLocation", name))
2997 return -1;
2998 if (IsPrefixReserved(name))
2999 return -1;
3000 if (!program->LinkStatus(this)) {
3001 SynthesizeGLError(GL_INVALID_OPERATION, "getAttribLocation",
3002 "program not linked");
3003 return 0;
3004 }
3005 return ContextGL()->GetAttribLocation(ObjectOrZero(program),
3006 name.Utf8().c_str());
3007 }
3008
ValidateBufferTarget(const char * function_name,GLenum target)3009 bool WebGLRenderingContextBase::ValidateBufferTarget(const char* function_name,
3010 GLenum target) {
3011 switch (target) {
3012 case GL_ARRAY_BUFFER:
3013 case GL_ELEMENT_ARRAY_BUFFER:
3014 return true;
3015 default:
3016 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
3017 return false;
3018 }
3019 }
3020
getBufferParameter(ScriptState * script_state,GLenum target,GLenum pname)3021 ScriptValue WebGLRenderingContextBase::getBufferParameter(
3022 ScriptState* script_state,
3023 GLenum target,
3024 GLenum pname) {
3025 if (isContextLost() || !ValidateBufferTarget("getBufferParameter", target))
3026 return ScriptValue::CreateNull(script_state->GetIsolate());
3027
3028 switch (pname) {
3029 case GL_BUFFER_USAGE: {
3030 GLint value = 0;
3031 ContextGL()->GetBufferParameteriv(target, pname, &value);
3032 return WebGLAny(script_state, static_cast<unsigned>(value));
3033 }
3034 case GL_BUFFER_SIZE: {
3035 GLint value = 0;
3036 ContextGL()->GetBufferParameteriv(target, pname, &value);
3037 if (!IsWebGL2())
3038 return WebGLAny(script_state, value);
3039 return WebGLAny(script_state, static_cast<GLint64>(value));
3040 }
3041 default:
3042 SynthesizeGLError(GL_INVALID_ENUM, "getBufferParameter",
3043 "invalid parameter name");
3044 return ScriptValue::CreateNull(script_state->GetIsolate());
3045 }
3046 }
3047
getContextAttributes() const3048 WebGLContextAttributes* WebGLRenderingContextBase::getContextAttributes()
3049 const {
3050 if (isContextLost())
3051 return nullptr;
3052
3053 WebGLContextAttributes* result =
3054 ToWebGLContextAttributes(CreationAttributes());
3055
3056 // Some requested attributes may not be honored, so we need to query the
3057 // underlying context/drawing buffer and adjust accordingly.
3058 if (CreationAttributes().depth && !GetDrawingBuffer()->HasDepthBuffer())
3059 result->setDepth(false);
3060 if (CreationAttributes().stencil && !GetDrawingBuffer()->HasStencilBuffer())
3061 result->setStencil(false);
3062 result->setAntialias(GetDrawingBuffer()->Multisample());
3063 result->setXrCompatible(xr_compatible_);
3064 result->setDesynchronized(Host()->LowLatencyEnabled());
3065 return result;
3066 }
3067
getError()3068 GLenum WebGLRenderingContextBase::getError() {
3069 if (!lost_context_errors_.IsEmpty()) {
3070 GLenum error = lost_context_errors_.front();
3071 lost_context_errors_.EraseAt(0);
3072 return error;
3073 }
3074
3075 if (isContextLost())
3076 return GL_NO_ERROR;
3077
3078 if (!synthetic_errors_.IsEmpty()) {
3079 GLenum error = synthetic_errors_.front();
3080 synthetic_errors_.EraseAt(0);
3081 return error;
3082 }
3083
3084 return ContextGL()->GetError();
3085 }
3086
Prefixes() const3087 const char* const* WebGLRenderingContextBase::ExtensionTracker::Prefixes()
3088 const {
3089 static const char* const kUnprefixed[] = {
3090 "",
3091 nullptr,
3092 };
3093 return prefixes_ ? prefixes_ : kUnprefixed;
3094 }
3095
MatchesNameWithPrefixes(const String & name) const3096 bool WebGLRenderingContextBase::ExtensionTracker::MatchesNameWithPrefixes(
3097 const String& name) const {
3098 const char* const* prefix_set = Prefixes();
3099 for (; *prefix_set; ++prefix_set) {
3100 String prefixed_name = String(*prefix_set) + ExtensionName();
3101 if (DeprecatedEqualIgnoringCase(prefixed_name, name)) {
3102 return true;
3103 }
3104 }
3105 return false;
3106 }
3107
ExtensionSupportedAndAllowed(const ExtensionTracker * tracker)3108 bool WebGLRenderingContextBase::ExtensionSupportedAndAllowed(
3109 const ExtensionTracker* tracker) {
3110 if (tracker->Draft() &&
3111 !RuntimeEnabledFeatures::WebGLDraftExtensionsEnabled())
3112 return false;
3113 if (!tracker->Supported(this))
3114 return false;
3115 if (disabled_extensions_.Contains(String(tracker->ExtensionName())))
3116 return false;
3117 return true;
3118 }
3119
getExtension(ScriptState * script_state,const String & name)3120 ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* script_state,
3121 const String& name) {
3122 WebGLExtension* extension = nullptr;
3123
3124 if (name == WebGLDebugRendererInfo::ExtensionName()) {
3125 ExecutionContext* context = ExecutionContext::From(script_state);
3126 UseCounter::Count(context, WebFeature::kWebGLDebugRendererInfo);
3127 Dactyloscoper::Record(context, WebFeature::kWebGLDebugRendererInfo);
3128 }
3129
3130 if (!isContextLost()) {
3131 for (ExtensionTracker* tracker : extensions_) {
3132 if (tracker->MatchesNameWithPrefixes(name)) {
3133 if (ExtensionSupportedAndAllowed(tracker)) {
3134 extension = tracker->GetExtension(this);
3135 if (extension) {
3136 if (!extension_enabled_[extension->GetName()]) {
3137 extension_enabled_[extension->GetName()] = true;
3138 }
3139 }
3140 }
3141 break;
3142 }
3143 }
3144 }
3145
3146 v8::Local<v8::Value> wrapped_extension =
3147 ToV8(extension, script_state->GetContext()->Global(),
3148 script_state->GetIsolate());
3149
3150 return ScriptValue(script_state->GetIsolate(), wrapped_extension);
3151 }
3152
getFramebufferAttachmentParameter(ScriptState * script_state,GLenum target,GLenum attachment,GLenum pname)3153 ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter(
3154 ScriptState* script_state,
3155 GLenum target,
3156 GLenum attachment,
3157 GLenum pname) {
3158 if (isContextLost() ||
3159 !ValidateFramebufferFuncParameters("getFramebufferAttachmentParameter",
3160 target, attachment))
3161 return ScriptValue::CreateNull(script_state->GetIsolate());
3162
3163 if (!framebuffer_binding_ || !framebuffer_binding_->Object()) {
3164 SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
3165 "no framebuffer bound");
3166 return ScriptValue::CreateNull(script_state->GetIsolate());
3167 }
3168
3169 if (framebuffer_binding_ && framebuffer_binding_->Opaque()) {
3170 SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
3171 "cannot query parameters of an opaque framebuffer");
3172 return ScriptValue::CreateNull(script_state->GetIsolate());
3173 }
3174
3175 WebGLSharedObject* attachment_object =
3176 framebuffer_binding_->GetAttachmentObject(attachment);
3177 if (!attachment_object) {
3178 if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
3179 return WebGLAny(script_state, GL_NONE);
3180 // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
3181 // specifies INVALID_OPERATION.
3182 SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3183 "invalid parameter name");
3184 return ScriptValue::CreateNull(script_state->GetIsolate());
3185 }
3186
3187 DCHECK(attachment_object->IsTexture() || attachment_object->IsRenderbuffer());
3188 if (attachment_object->IsTexture()) {
3189 switch (pname) {
3190 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3191 return WebGLAny(script_state, GL_TEXTURE);
3192 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3193 return WebGLAny(script_state, attachment_object);
3194 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3195 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
3196 GLint value = 0;
3197 ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
3198 pname, &value);
3199 return WebGLAny(script_state, value);
3200 }
3201 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
3202 if (ExtensionEnabled(kEXTsRGBName)) {
3203 GLint value = 0;
3204 ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
3205 pname, &value);
3206 return WebGLAny(script_state, static_cast<unsigned>(value));
3207 }
3208 SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3209 "invalid parameter name for renderbuffer attachment");
3210 return ScriptValue::CreateNull(script_state->GetIsolate());
3211 default:
3212 SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3213 "invalid parameter name for texture attachment");
3214 return ScriptValue::CreateNull(script_state->GetIsolate());
3215 }
3216 } else {
3217 switch (pname) {
3218 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3219 return WebGLAny(script_state, GL_RENDERBUFFER);
3220 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3221 return WebGLAny(script_state, attachment_object);
3222 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
3223 if (ExtensionEnabled(kEXTsRGBName)) {
3224 GLint value = 0;
3225 ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
3226 pname, &value);
3227 return WebGLAny(script_state, value);
3228 }
3229 SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3230 "invalid parameter name for renderbuffer attachment");
3231 return ScriptValue::CreateNull(script_state->GetIsolate());
3232 default:
3233 SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3234 "invalid parameter name for renderbuffer attachment");
3235 return ScriptValue::CreateNull(script_state->GetIsolate());
3236 }
3237 }
3238 }
3239
3240 namespace {
3241
3242 // WebGL parameters which can be used to identify users.
3243 // These parameters should each be uniquely defined,
3244 // see third_party/khronos/GLES2/gl2.h for their definitions.
3245 static const GLenum kIdentifiableGLParams[] = {
3246 // getParameter()
3247 GL_ALIASED_LINE_WIDTH_RANGE, // GetWebGLFloatArrayParameter
3248 GL_ALIASED_POINT_SIZE_RANGE, // GetWebGLFloatArrayParameter
3249 GL_ALPHA_BITS, // GetIntParameter
3250 GL_BLUE_BITS, // GetIntParameter
3251 GL_DEPTH_BITS, // GetIntParameter
3252 GL_GREEN_BITS, // GetIntParameter
3253 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, // GetIntParameter
3254 GL_MAX_CUBE_MAP_TEXTURE_SIZE, // GetIntParameter
3255 GL_MAX_FRAGMENT_UNIFORM_VECTORS, // GetIntParameter
3256 GL_MAX_RENDERBUFFER_SIZE, // GetIntParameter
3257 GL_MAX_TEXTURE_IMAGE_UNITS, // GetIntParameter
3258 GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, // GetFloatParameter
3259 GL_MAX_TEXTURE_SIZE, // GetIntParameter
3260 GL_MAX_VARYING_VECTORS, // GetIntParameter
3261 GL_MAX_VERTEX_ATTRIBS, // GetIntParameter
3262 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, // GetIntParameter
3263 GL_MAX_VERTEX_UNIFORM_VECTORS, // GetIntParameter
3264 GL_MAX_VIEWPORT_DIMS, // GetWebGLIntArrayParameter
3265 GL_RED_BITS, // GetIntParameter
3266 GL_SHADING_LANGUAGE_VERSION,
3267 GL_STENCIL_BITS, // GetIntParameter
3268 GL_VERSION,
3269 WebGLDebugRendererInfo::kUnmaskedRendererWebgl,
3270 WebGLDebugRendererInfo::kUnmaskedVendorWebgl,
3271
3272 // getRenderBufferParameter()
3273 GL_RENDERBUFFER_GREEN_SIZE,
3274 GL_RENDERBUFFER_BLUE_SIZE,
3275 GL_RENDERBUFFER_RED_SIZE,
3276 GL_RENDERBUFFER_ALPHA_SIZE,
3277 GL_RENDERBUFFER_DEPTH_SIZE,
3278 GL_RENDERBUFFER_STENCIL_SIZE,
3279 GL_RENDERBUFFER_SAMPLES,
3280 };
3281
ShouldMeasureGLParam(GLenum pname)3282 bool ShouldMeasureGLParam(GLenum pname) {
3283 return IdentifiabilityStudySettings::Get()->ShouldSample(
3284 blink::IdentifiableSurface::Type::kWebGLParameter) &&
3285 std::find(std::begin(kIdentifiableGLParams),
3286 std::end(kIdentifiableGLParams),
3287 pname) != std::end(kIdentifiableGLParams);
3288 }
3289
3290 } // namespace
3291
RecordIdentifiableGLParameterDigest(GLenum pname,IdentifiableToken value)3292 void WebGLRenderingContextBase::RecordIdentifiableGLParameterDigest(
3293 GLenum pname,
3294 IdentifiableToken value) {
3295 DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
3296 blink::IdentifiableSurface::Type::kWebGLParameter));
3297 const auto ukm_params = GetUkmParameters();
3298 blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
3299 .Set(blink::IdentifiableSurface::FromTypeAndToken(
3300 blink::IdentifiableSurface::Type::kWebGLParameter, pname),
3301 value)
3302 .Record(ukm_params.ukm_recorder);
3303 }
3304
RecordShaderPrecisionFormatForStudy(GLenum shader_type,GLenum precision_type,WebGLShaderPrecisionFormat * format)3305 void WebGLRenderingContextBase::RecordShaderPrecisionFormatForStudy(
3306 GLenum shader_type,
3307 GLenum precision_type,
3308 WebGLShaderPrecisionFormat* format) {
3309 DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
3310 blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat));
3311
3312 const auto& ukm_params = GetUkmParameters();
3313 IdentifiableTokenBuilder builder;
3314 auto surface_token =
3315 builder.AddValue(shader_type).AddValue(precision_type).GetToken();
3316 auto sample_token = builder.AddValue(format->rangeMin())
3317 .AddValue(format->rangeMax())
3318 .AddValue(format->precision())
3319 .GetToken();
3320
3321 blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
3322 .Set(blink::IdentifiableSurface::FromTypeAndToken(
3323 blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat,
3324 surface_token),
3325 sample_token)
3326 .Record(ukm_params.ukm_recorder);
3327 }
3328
getParameter(ScriptState * script_state,GLenum pname)3329 ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
3330 GLenum pname) {
3331 if (isContextLost())
3332 return ScriptValue::CreateNull(script_state->GetIsolate());
3333 const int kIntZero = 0;
3334 switch (pname) {
3335 case GL_ACTIVE_TEXTURE:
3336 return GetUnsignedIntParameter(script_state, pname);
3337 case GL_ALIASED_LINE_WIDTH_RANGE:
3338 return GetWebGLFloatArrayParameter(script_state, pname);
3339 case GL_ALIASED_POINT_SIZE_RANGE:
3340 return GetWebGLFloatArrayParameter(script_state, pname);
3341 case GL_ALPHA_BITS:
3342 if (drawing_buffer_->RequiresAlphaChannelToBePreserved())
3343 return WebGLAny(script_state, 0);
3344 return GetIntParameter(script_state, pname);
3345 case GL_ARRAY_BUFFER_BINDING:
3346 return WebGLAny(script_state, bound_array_buffer_.Get());
3347 case GL_BLEND:
3348 return GetBooleanParameter(script_state, pname);
3349 case GL_BLEND_COLOR:
3350 return GetWebGLFloatArrayParameter(script_state, pname);
3351 case GL_BLEND_DST_ALPHA:
3352 return GetUnsignedIntParameter(script_state, pname);
3353 case GL_BLEND_DST_RGB:
3354 return GetUnsignedIntParameter(script_state, pname);
3355 case GL_BLEND_EQUATION_ALPHA:
3356 return GetUnsignedIntParameter(script_state, pname);
3357 case GL_BLEND_EQUATION_RGB:
3358 return GetUnsignedIntParameter(script_state, pname);
3359 case GL_BLEND_SRC_ALPHA:
3360 return GetUnsignedIntParameter(script_state, pname);
3361 case GL_BLEND_SRC_RGB:
3362 return GetUnsignedIntParameter(script_state, pname);
3363 case GL_BLUE_BITS:
3364 return GetIntParameter(script_state, pname);
3365 case GL_COLOR_CLEAR_VALUE:
3366 return GetWebGLFloatArrayParameter(script_state, pname);
3367 case GL_COLOR_WRITEMASK:
3368 return GetBooleanArrayParameter(script_state, pname);
3369 case GL_COMPRESSED_TEXTURE_FORMATS:
3370 return WebGLAny(script_state, DOMUint32Array::Create(
3371 compressed_texture_formats_.data(),
3372 compressed_texture_formats_.size()));
3373 case GL_CULL_FACE:
3374 return GetBooleanParameter(script_state, pname);
3375 case GL_CULL_FACE_MODE:
3376 return GetUnsignedIntParameter(script_state, pname);
3377 case GL_CURRENT_PROGRAM:
3378 return WebGLAny(script_state, current_program_.Get());
3379 case GL_DEPTH_BITS:
3380 if (!framebuffer_binding_ && !CreationAttributes().depth)
3381 return WebGLAny(script_state, kIntZero);
3382 return GetIntParameter(script_state, pname);
3383 case GL_DEPTH_CLEAR_VALUE:
3384 return GetFloatParameter(script_state, pname);
3385 case GL_DEPTH_FUNC:
3386 return GetUnsignedIntParameter(script_state, pname);
3387 case GL_DEPTH_RANGE:
3388 return GetWebGLFloatArrayParameter(script_state, pname);
3389 case GL_DEPTH_TEST:
3390 return GetBooleanParameter(script_state, pname);
3391 case GL_DEPTH_WRITEMASK:
3392 return GetBooleanParameter(script_state, pname);
3393 case GL_DITHER:
3394 return GetBooleanParameter(script_state, pname);
3395 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
3396 return WebGLAny(script_state,
3397 bound_vertex_array_object_->BoundElementArrayBuffer());
3398 case GL_FRAMEBUFFER_BINDING:
3399 return WebGLAny(script_state, framebuffer_binding_.Get());
3400 case GL_FRONT_FACE:
3401 return GetUnsignedIntParameter(script_state, pname);
3402 case GL_GENERATE_MIPMAP_HINT:
3403 return GetUnsignedIntParameter(script_state, pname);
3404 case GL_GREEN_BITS:
3405 return GetIntParameter(script_state, pname);
3406 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
3407 return GetIntParameter(script_state, pname);
3408 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
3409 return GetIntParameter(script_state, pname);
3410 case GL_LINE_WIDTH:
3411 return GetFloatParameter(script_state, pname);
3412 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
3413 return GetIntParameter(script_state, pname);
3414 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
3415 return GetIntParameter(script_state, pname);
3416 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
3417 return GetIntParameter(script_state, pname);
3418 case GL_MAX_RENDERBUFFER_SIZE:
3419 return GetIntParameter(script_state, pname);
3420 case GL_MAX_TEXTURE_IMAGE_UNITS:
3421 return GetIntParameter(script_state, pname);
3422 case GL_MAX_TEXTURE_SIZE:
3423 return GetIntParameter(script_state, pname);
3424 case GL_MAX_VARYING_VECTORS:
3425 return GetIntParameter(script_state, pname);
3426 case GL_MAX_VERTEX_ATTRIBS:
3427 return GetIntParameter(script_state, pname);
3428 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
3429 return GetIntParameter(script_state, pname);
3430 case GL_MAX_VERTEX_UNIFORM_VECTORS:
3431 return GetIntParameter(script_state, pname);
3432 case GL_MAX_VIEWPORT_DIMS:
3433 return GetWebGLIntArrayParameter(script_state, pname);
3434 case GL_NUM_SHADER_BINARY_FORMATS:
3435 // FIXME: should we always return 0 for this?
3436 return GetIntParameter(script_state, pname);
3437 case GL_PACK_ALIGNMENT:
3438 return GetIntParameter(script_state, pname);
3439 case GL_POLYGON_OFFSET_FACTOR:
3440 return GetFloatParameter(script_state, pname);
3441 case GL_POLYGON_OFFSET_FILL:
3442 return GetBooleanParameter(script_state, pname);
3443 case GL_POLYGON_OFFSET_UNITS:
3444 return GetFloatParameter(script_state, pname);
3445 case GL_RED_BITS:
3446 return GetIntParameter(script_state, pname);
3447 case GL_RENDERBUFFER_BINDING:
3448 return WebGLAny(script_state, renderbuffer_binding_.Get());
3449 case GL_RENDERER:
3450 return WebGLAny(script_state, String("WebKit WebGL"));
3451 case GL_SAMPLE_ALPHA_TO_COVERAGE:
3452 return GetBooleanParameter(script_state, pname);
3453 case GL_SAMPLE_BUFFERS:
3454 return GetIntParameter(script_state, pname);
3455 case GL_SAMPLE_COVERAGE:
3456 return GetBooleanParameter(script_state, pname);
3457 case GL_SAMPLE_COVERAGE_INVERT:
3458 return GetBooleanParameter(script_state, pname);
3459 case GL_SAMPLE_COVERAGE_VALUE:
3460 return GetFloatParameter(script_state, pname);
3461 case GL_SAMPLES:
3462 return GetIntParameter(script_state, pname);
3463 case GL_SCISSOR_BOX:
3464 return GetWebGLIntArrayParameter(script_state, pname);
3465 case GL_SCISSOR_TEST:
3466 return GetBooleanParameter(script_state, pname);
3467 case GL_SHADING_LANGUAGE_VERSION:
3468 if (IdentifiabilityStudySettings::Get()->ShouldSample(
3469 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3470 RecordIdentifiableGLParameterDigest(
3471 pname, IdentifiabilityBenignStringToken(String(
3472 ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION))));
3473 }
3474 return WebGLAny(
3475 script_state,
3476 "WebGL GLSL ES 1.0 (" +
3477 String(ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION)) +
3478 ")");
3479 case GL_STENCIL_BACK_FAIL:
3480 return GetUnsignedIntParameter(script_state, pname);
3481 case GL_STENCIL_BACK_FUNC:
3482 return GetUnsignedIntParameter(script_state, pname);
3483 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
3484 return GetUnsignedIntParameter(script_state, pname);
3485 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
3486 return GetUnsignedIntParameter(script_state, pname);
3487 case GL_STENCIL_BACK_REF:
3488 return GetIntParameter(script_state, pname);
3489 case GL_STENCIL_BACK_VALUE_MASK:
3490 return GetUnsignedIntParameter(script_state, pname);
3491 case GL_STENCIL_BACK_WRITEMASK:
3492 return GetUnsignedIntParameter(script_state, pname);
3493 case GL_STENCIL_BITS:
3494 if (!framebuffer_binding_ && !CreationAttributes().stencil)
3495 return WebGLAny(script_state, kIntZero);
3496 return GetIntParameter(script_state, pname);
3497 case GL_STENCIL_CLEAR_VALUE:
3498 return GetIntParameter(script_state, pname);
3499 case GL_STENCIL_FAIL:
3500 return GetUnsignedIntParameter(script_state, pname);
3501 case GL_STENCIL_FUNC:
3502 return GetUnsignedIntParameter(script_state, pname);
3503 case GL_STENCIL_PASS_DEPTH_FAIL:
3504 return GetUnsignedIntParameter(script_state, pname);
3505 case GL_STENCIL_PASS_DEPTH_PASS:
3506 return GetUnsignedIntParameter(script_state, pname);
3507 case GL_STENCIL_REF:
3508 return GetIntParameter(script_state, pname);
3509 case GL_STENCIL_TEST:
3510 return WebGLAny(script_state, stencil_enabled_);
3511 case GL_STENCIL_VALUE_MASK:
3512 return GetUnsignedIntParameter(script_state, pname);
3513 case GL_STENCIL_WRITEMASK:
3514 return GetUnsignedIntParameter(script_state, pname);
3515 case GL_SUBPIXEL_BITS:
3516 return GetIntParameter(script_state, pname);
3517 case GL_TEXTURE_BINDING_2D:
3518 return WebGLAny(
3519 script_state,
3520 texture_units_[active_texture_unit_].texture2d_binding_.Get());
3521 case GL_TEXTURE_BINDING_CUBE_MAP:
3522 return WebGLAny(
3523 script_state,
3524 texture_units_[active_texture_unit_].texture_cube_map_binding_.Get());
3525 case GL_UNPACK_ALIGNMENT:
3526 return GetIntParameter(script_state, pname);
3527 case GC3D_UNPACK_FLIP_Y_WEBGL:
3528 return WebGLAny(script_state, unpack_flip_y_);
3529 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3530 return WebGLAny(script_state, unpack_premultiply_alpha_);
3531 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
3532 return WebGLAny(script_state, unpack_colorspace_conversion_);
3533 case GL_VENDOR:
3534 return WebGLAny(script_state, String("WebKit"));
3535 case GL_VERSION:
3536 if (IdentifiabilityStudySettings::Get()->ShouldSample(
3537 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3538 RecordIdentifiableGLParameterDigest(
3539 pname, IdentifiabilityBenignStringToken(
3540 String(ContextGL()->GetString(GL_VERSION))));
3541 }
3542 return WebGLAny(
3543 script_state,
3544 "WebGL 1.0 (" + String(ContextGL()->GetString(GL_VERSION)) + ")");
3545 case GL_VIEWPORT:
3546 return GetWebGLIntArrayParameter(script_state, pname);
3547 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
3548 if (ExtensionEnabled(kOESStandardDerivativesName) || IsWebGL2())
3549 return GetUnsignedIntParameter(script_state,
3550 GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
3551 SynthesizeGLError(
3552 GL_INVALID_ENUM, "getParameter",
3553 "invalid parameter name, OES_standard_derivatives not enabled");
3554 return ScriptValue::CreateNull(script_state->GetIsolate());
3555 case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:
3556 if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
3557 if (IdentifiabilityStudySettings::Get()->ShouldSample(
3558 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3559 RecordIdentifiableGLParameterDigest(
3560 pname, IdentifiabilityBenignStringToken(
3561 String(ContextGL()->GetString(GL_RENDERER))));
3562 }
3563 return WebGLAny(script_state,
3564 String(ContextGL()->GetString(GL_RENDERER)));
3565 }
3566 SynthesizeGLError(
3567 GL_INVALID_ENUM, "getParameter",
3568 "invalid parameter name, WEBGL_debug_renderer_info not enabled");
3569 return ScriptValue::CreateNull(script_state->GetIsolate());
3570 case WebGLDebugRendererInfo::kUnmaskedVendorWebgl:
3571 if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
3572 if (IdentifiabilityStudySettings::Get()->ShouldSample(
3573 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3574 RecordIdentifiableGLParameterDigest(
3575 pname, IdentifiabilityBenignStringToken(
3576 String(ContextGL()->GetString(GL_VENDOR))));
3577 }
3578 return WebGLAny(script_state,
3579 String(ContextGL()->GetString(GL_VENDOR)));
3580 }
3581 SynthesizeGLError(
3582 GL_INVALID_ENUM, "getParameter",
3583 "invalid parameter name, WEBGL_debug_renderer_info not enabled");
3584 return ScriptValue::CreateNull(script_state->GetIsolate());
3585 case GL_VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
3586 if (ExtensionEnabled(kOESVertexArrayObjectName) || IsWebGL2()) {
3587 if (!bound_vertex_array_object_->IsDefaultObject())
3588 return WebGLAny(script_state, bound_vertex_array_object_.Get());
3589 return ScriptValue::CreateNull(script_state->GetIsolate());
3590 }
3591 SynthesizeGLError(
3592 GL_INVALID_ENUM, "getParameter",
3593 "invalid parameter name, OES_vertex_array_object not enabled");
3594 return ScriptValue::CreateNull(script_state->GetIsolate());
3595 case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3596 if (ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
3597 return GetFloatParameter(script_state,
3598 GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
3599 }
3600 SynthesizeGLError(
3601 GL_INVALID_ENUM, "getParameter",
3602 "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
3603 return ScriptValue::CreateNull(script_state->GetIsolate());
3604 case GL_MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
3605 if (ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2())
3606 return WebGLAny(script_state, MaxColorAttachments());
3607 SynthesizeGLError(
3608 GL_INVALID_ENUM, "getParameter",
3609 "invalid parameter name, WEBGL_draw_buffers not enabled");
3610 return ScriptValue::CreateNull(script_state->GetIsolate());
3611 case GL_MAX_DRAW_BUFFERS_EXT:
3612 if (ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2())
3613 return WebGLAny(script_state, MaxDrawBuffers());
3614 SynthesizeGLError(
3615 GL_INVALID_ENUM, "getParameter",
3616 "invalid parameter name, WEBGL_draw_buffers not enabled");
3617 return ScriptValue::CreateNull(script_state->GetIsolate());
3618 case GL_TIMESTAMP_EXT:
3619 if (ExtensionEnabled(kEXTDisjointTimerQueryName))
3620 return WebGLAny(script_state, 0);
3621 SynthesizeGLError(
3622 GL_INVALID_ENUM, "getParameter",
3623 "invalid parameter name, EXT_disjoint_timer_query not enabled");
3624 return ScriptValue::CreateNull(script_state->GetIsolate());
3625 case GL_GPU_DISJOINT_EXT:
3626 if (ExtensionEnabled(kEXTDisjointTimerQueryName))
3627 return GetBooleanParameter(script_state, GL_GPU_DISJOINT_EXT);
3628 SynthesizeGLError(
3629 GL_INVALID_ENUM, "getParameter",
3630 "invalid parameter name, EXT_disjoint_timer_query not enabled");
3631 return ScriptValue::CreateNull(script_state->GetIsolate());
3632 case GL_MAX_VIEWS_OVR:
3633 if (ExtensionEnabled(kOVRMultiview2Name))
3634 return GetIntParameter(script_state, pname);
3635 SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
3636 "invalid parameter name, OVR_multiview2 not enabled");
3637 return ScriptValue::CreateNull(script_state->GetIsolate());
3638 default:
3639 if ((ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()) &&
3640 pname >= GL_DRAW_BUFFER0_EXT &&
3641 pname < static_cast<GLenum>(GL_DRAW_BUFFER0_EXT + MaxDrawBuffers())) {
3642 GLint value = GL_NONE;
3643 if (framebuffer_binding_)
3644 value = framebuffer_binding_->GetDrawBuffer(pname);
3645 else // emulated backbuffer
3646 value = back_draw_buffer_;
3647 return WebGLAny(script_state, value);
3648 }
3649 SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
3650 "invalid parameter name");
3651 return ScriptValue::CreateNull(script_state->GetIsolate());
3652 }
3653 }
3654
getProgramParameter(ScriptState * script_state,WebGLProgram * program,GLenum pname)3655 ScriptValue WebGLRenderingContextBase::getProgramParameter(
3656 ScriptState* script_state,
3657 WebGLProgram* program,
3658 GLenum pname) {
3659 if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) {
3660 return ScriptValue::CreateNull(script_state->GetIsolate());
3661 }
3662
3663 GLint value = 0;
3664 switch (pname) {
3665 case GL_DELETE_STATUS:
3666 return WebGLAny(script_state, program->MarkedForDeletion());
3667 case GL_VALIDATE_STATUS:
3668 ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
3669 return WebGLAny(script_state, static_cast<bool>(value));
3670 case GL_LINK_STATUS:
3671 return WebGLAny(script_state, program->LinkStatus(this));
3672 case GL_COMPLETION_STATUS_KHR:
3673 if (!ExtensionEnabled(kKHRParallelShaderCompileName)) {
3674 SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3675 "invalid parameter name");
3676 return ScriptValue::CreateNull(script_state->GetIsolate());
3677 }
3678 bool completed;
3679 if (checkProgramCompletionQueryAvailable(program, &completed)) {
3680 return WebGLAny(script_state, completed);
3681 }
3682 return WebGLAny(script_state, program->CompletionStatus(this));
3683 case GL_ACTIVE_UNIFORM_BLOCKS:
3684 case GL_TRANSFORM_FEEDBACK_VARYINGS:
3685 if (!IsWebGL2()) {
3686 SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3687 "invalid parameter name");
3688 return ScriptValue::CreateNull(script_state->GetIsolate());
3689 }
3690 FALLTHROUGH;
3691 case GL_ATTACHED_SHADERS:
3692 case GL_ACTIVE_ATTRIBUTES:
3693 case GL_ACTIVE_UNIFORMS:
3694 ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
3695 return WebGLAny(script_state, value);
3696 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
3697 if (!IsWebGL2()) {
3698 SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3699 "invalid parameter name");
3700 return ScriptValue::CreateNull(script_state->GetIsolate());
3701 }
3702 ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
3703 return WebGLAny(script_state, static_cast<unsigned>(value));
3704 default:
3705 SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3706 "invalid parameter name");
3707 return ScriptValue::CreateNull(script_state->GetIsolate());
3708 }
3709 }
3710
getProgramInfoLog(WebGLProgram * program)3711 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program) {
3712 if (!ValidateWebGLProgramOrShader("getProgramInfoLog", program))
3713 return String();
3714 GLStringQuery query(ContextGL());
3715 return query.Run<GLStringQuery::ProgramInfoLog>(ObjectNonZero(program));
3716 }
3717
getRenderbufferParameter(ScriptState * script_state,GLenum target,GLenum pname)3718 ScriptValue WebGLRenderingContextBase::getRenderbufferParameter(
3719 ScriptState* script_state,
3720 GLenum target,
3721 GLenum pname) {
3722 if (isContextLost())
3723 return ScriptValue::CreateNull(script_state->GetIsolate());
3724 if (target != GL_RENDERBUFFER) {
3725 SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
3726 "invalid target");
3727 return ScriptValue::CreateNull(script_state->GetIsolate());
3728 }
3729 if (!renderbuffer_binding_ || !renderbuffer_binding_->Object()) {
3730 SynthesizeGLError(GL_INVALID_OPERATION, "getRenderbufferParameter",
3731 "no renderbuffer bound");
3732 return ScriptValue::CreateNull(script_state->GetIsolate());
3733 }
3734
3735 GLint value = 0;
3736 switch (pname) {
3737 case GL_RENDERBUFFER_SAMPLES:
3738 if (!IsWebGL2()) {
3739 SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
3740 "invalid parameter name");
3741 return ScriptValue::CreateNull(script_state->GetIsolate());
3742 }
3743 FALLTHROUGH;
3744 case GL_RENDERBUFFER_WIDTH:
3745 case GL_RENDERBUFFER_HEIGHT:
3746 case GL_RENDERBUFFER_RED_SIZE:
3747 case GL_RENDERBUFFER_GREEN_SIZE:
3748 case GL_RENDERBUFFER_BLUE_SIZE:
3749 case GL_RENDERBUFFER_ALPHA_SIZE:
3750 case GL_RENDERBUFFER_DEPTH_SIZE:
3751 case GL_RENDERBUFFER_STENCIL_SIZE:
3752 ContextGL()->GetRenderbufferParameteriv(target, pname, &value);
3753 if (IdentifiabilityStudySettings::Get()->ShouldSample(
3754 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3755 RecordIdentifiableGLParameterDigest(pname, value);
3756 }
3757 return WebGLAny(script_state, value);
3758 case GL_RENDERBUFFER_INTERNAL_FORMAT:
3759 return WebGLAny(script_state, renderbuffer_binding_->InternalFormat());
3760 default:
3761 SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
3762 "invalid parameter name");
3763 return ScriptValue::CreateNull(script_state->GetIsolate());
3764 }
3765 }
3766
getShaderParameter(ScriptState * script_state,WebGLShader * shader,GLenum pname)3767 ScriptValue WebGLRenderingContextBase::getShaderParameter(
3768 ScriptState* script_state,
3769 WebGLShader* shader,
3770 GLenum pname) {
3771 if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) {
3772 return ScriptValue::CreateNull(script_state->GetIsolate());
3773 }
3774 GLint value = 0;
3775 switch (pname) {
3776 case GL_DELETE_STATUS:
3777 return WebGLAny(script_state, shader->MarkedForDeletion());
3778 case GL_COMPILE_STATUS:
3779 ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
3780 return WebGLAny(script_state, static_cast<bool>(value));
3781 case GL_COMPLETION_STATUS_KHR:
3782 if (!ExtensionEnabled(kKHRParallelShaderCompileName)) {
3783 SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter",
3784 "invalid parameter name");
3785 return ScriptValue::CreateNull(script_state->GetIsolate());
3786 }
3787 ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
3788 return WebGLAny(script_state, static_cast<bool>(value));
3789 case GL_SHADER_TYPE:
3790 ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
3791 return WebGLAny(script_state, static_cast<unsigned>(value));
3792 default:
3793 SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter",
3794 "invalid parameter name");
3795 return ScriptValue::CreateNull(script_state->GetIsolate());
3796 }
3797 }
3798
getShaderInfoLog(WebGLShader * shader)3799 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) {
3800 if (!ValidateWebGLProgramOrShader("getShaderInfoLog", shader))
3801 return String();
3802 GLStringQuery query(ContextGL());
3803 return query.Run<GLStringQuery::ShaderInfoLog>(ObjectNonZero(shader));
3804 }
3805
getShaderPrecisionFormat(GLenum shader_type,GLenum precision_type)3806 WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat(
3807 GLenum shader_type,
3808 GLenum precision_type) {
3809 if (isContextLost())
3810 return nullptr;
3811 if (!ValidateShaderType("getShaderPrecisionFormat", shader_type)) {
3812 return nullptr;
3813 }
3814 switch (precision_type) {
3815 case GL_LOW_FLOAT:
3816 case GL_MEDIUM_FLOAT:
3817 case GL_HIGH_FLOAT:
3818 case GL_LOW_INT:
3819 case GL_MEDIUM_INT:
3820 case GL_HIGH_INT:
3821 break;
3822 default:
3823 SynthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat",
3824 "invalid precision type");
3825 return nullptr;
3826 }
3827
3828 GLint range[2] = {0, 0};
3829 GLint precision = 0;
3830 ContextGL()->GetShaderPrecisionFormat(shader_type, precision_type, range,
3831 &precision);
3832 auto* result = MakeGarbageCollected<WebGLShaderPrecisionFormat>(
3833 range[0], range[1], precision);
3834 if (IdentifiabilityStudySettings::Get()->ShouldSample(
3835 blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat)) {
3836 RecordShaderPrecisionFormatForStudy(shader_type, precision_type, result);
3837 }
3838 return result;
3839 }
3840
getShaderSource(WebGLShader * shader)3841 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) {
3842 if (!ValidateWebGLProgramOrShader("getShaderSource", shader))
3843 return String();
3844 return EnsureNotNull(shader->Source());
3845 }
3846
3847 base::Optional<Vector<String>>
getSupportedExtensions()3848 WebGLRenderingContextBase::getSupportedExtensions() {
3849 if (isContextLost())
3850 return base::nullopt;
3851
3852 Vector<String> result;
3853
3854 for (ExtensionTracker* tracker : extensions_) {
3855 if (ExtensionSupportedAndAllowed(tracker)) {
3856 const char* const* prefixes = tracker->Prefixes();
3857 for (; *prefixes; ++prefixes) {
3858 String prefixed_name = String(*prefixes) + tracker->ExtensionName();
3859 result.push_back(prefixed_name);
3860 }
3861 }
3862 }
3863
3864 return result;
3865 }
3866
getTexParameter(ScriptState * script_state,GLenum target,GLenum pname)3867 ScriptValue WebGLRenderingContextBase::getTexParameter(
3868 ScriptState* script_state,
3869 GLenum target,
3870 GLenum pname) {
3871 if (isContextLost())
3872 return ScriptValue::CreateNull(script_state->GetIsolate());
3873 if (!ValidateTextureBinding("getTexParameter", target))
3874 return ScriptValue::CreateNull(script_state->GetIsolate());
3875 switch (pname) {
3876 case GL_TEXTURE_MAG_FILTER:
3877 case GL_TEXTURE_MIN_FILTER:
3878 case GL_TEXTURE_WRAP_S:
3879 case GL_TEXTURE_WRAP_T: {
3880 GLint value = 0;
3881 ContextGL()->GetTexParameteriv(target, pname, &value);
3882 return WebGLAny(script_state, static_cast<unsigned>(value));
3883 }
3884 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3885 if (ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
3886 GLfloat value = 0.f;
3887 ContextGL()->GetTexParameterfv(target, pname, &value);
3888 return WebGLAny(script_state, value);
3889 }
3890 SynthesizeGLError(
3891 GL_INVALID_ENUM, "getTexParameter",
3892 "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
3893 return ScriptValue::CreateNull(script_state->GetIsolate());
3894 default:
3895 SynthesizeGLError(GL_INVALID_ENUM, "getTexParameter",
3896 "invalid parameter name");
3897 return ScriptValue::CreateNull(script_state->GetIsolate());
3898 }
3899 }
3900
getUniform(ScriptState * script_state,WebGLProgram * program,const WebGLUniformLocation * uniform_location)3901 ScriptValue WebGLRenderingContextBase::getUniform(
3902 ScriptState* script_state,
3903 WebGLProgram* program,
3904 const WebGLUniformLocation* uniform_location) {
3905 if (!ValidateWebGLProgramOrShader("getUniform", program))
3906 return ScriptValue::CreateNull(script_state->GetIsolate());
3907 DCHECK(uniform_location);
3908 if (uniform_location->Program() != program) {
3909 SynthesizeGLError(GL_INVALID_OPERATION, "getUniform",
3910 "no uniformlocation or not valid for this program");
3911 return ScriptValue::CreateNull(script_state->GetIsolate());
3912 }
3913 GLint location = uniform_location->Location();
3914
3915 GLuint program_id = ObjectNonZero(program);
3916 GLint max_name_length = -1;
3917 ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH,
3918 &max_name_length);
3919 if (max_name_length < 0)
3920 return ScriptValue::CreateNull(script_state->GetIsolate());
3921 if (max_name_length == 0) {
3922 SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
3923 "no active uniforms exist");
3924 return ScriptValue::CreateNull(script_state->GetIsolate());
3925 }
3926
3927 // FIXME: make this more efficient using WebGLUniformLocation and caching
3928 // types in it.
3929 GLint active_uniforms = 0;
3930 ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORMS, &active_uniforms);
3931 for (GLint i = 0; i < active_uniforms; i++) {
3932 LChar* name_ptr;
3933 scoped_refptr<StringImpl> name_impl =
3934 StringImpl::CreateUninitialized(max_name_length, name_ptr);
3935 GLsizei name_length = 0;
3936 GLint size = -1;
3937 GLenum type = 0;
3938 ContextGL()->GetActiveUniform(program_id, i, max_name_length, &name_length,
3939 &size, &type,
3940 reinterpret_cast<GLchar*>(name_ptr));
3941 if (size < 0)
3942 return ScriptValue::CreateNull(script_state->GetIsolate());
3943 String name(name_impl->Substring(0, name_length));
3944 StringBuilder name_builder;
3945 // Strip "[0]" from the name if it's an array.
3946 if (size > 1 && name.EndsWith("[0]"))
3947 name = name.Left(name.length() - 3);
3948 // If it's an array, we need to iterate through each element, appending
3949 // "[index]" to the name.
3950 for (GLint index = 0; index < size; ++index) {
3951 name_builder.Clear();
3952 name_builder.Append(name);
3953 if (size > 1 && index >= 1) {
3954 name_builder.Append('[');
3955 name_builder.AppendNumber(index);
3956 name_builder.Append(']');
3957 }
3958 // Now need to look this up by name again to find its location
3959 GLint loc = ContextGL()->GetUniformLocation(
3960 ObjectOrZero(program), name_builder.ToString().Utf8().c_str());
3961 if (loc == location) {
3962 // Found it. Use the type in the ActiveInfo to determine the return
3963 // type.
3964 GLenum base_type;
3965 unsigned length;
3966 switch (type) {
3967 case GL_BOOL:
3968 base_type = GL_BOOL;
3969 length = 1;
3970 break;
3971 case GL_BOOL_VEC2:
3972 base_type = GL_BOOL;
3973 length = 2;
3974 break;
3975 case GL_BOOL_VEC3:
3976 base_type = GL_BOOL;
3977 length = 3;
3978 break;
3979 case GL_BOOL_VEC4:
3980 base_type = GL_BOOL;
3981 length = 4;
3982 break;
3983 case GL_INT:
3984 base_type = GL_INT;
3985 length = 1;
3986 break;
3987 case GL_INT_VEC2:
3988 base_type = GL_INT;
3989 length = 2;
3990 break;
3991 case GL_INT_VEC3:
3992 base_type = GL_INT;
3993 length = 3;
3994 break;
3995 case GL_INT_VEC4:
3996 base_type = GL_INT;
3997 length = 4;
3998 break;
3999 case GL_FLOAT:
4000 base_type = GL_FLOAT;
4001 length = 1;
4002 break;
4003 case GL_FLOAT_VEC2:
4004 base_type = GL_FLOAT;
4005 length = 2;
4006 break;
4007 case GL_FLOAT_VEC3:
4008 base_type = GL_FLOAT;
4009 length = 3;
4010 break;
4011 case GL_FLOAT_VEC4:
4012 base_type = GL_FLOAT;
4013 length = 4;
4014 break;
4015 case GL_FLOAT_MAT2:
4016 base_type = GL_FLOAT;
4017 length = 4;
4018 break;
4019 case GL_FLOAT_MAT3:
4020 base_type = GL_FLOAT;
4021 length = 9;
4022 break;
4023 case GL_FLOAT_MAT4:
4024 base_type = GL_FLOAT;
4025 length = 16;
4026 break;
4027 case GL_SAMPLER_2D:
4028 case GL_SAMPLER_CUBE:
4029 base_type = GL_INT;
4030 length = 1;
4031 break;
4032 case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
4033 if (!ExtensionEnabled(kWebGLVideoTextureName)) {
4034 SynthesizeGLError(
4035 GL_INVALID_VALUE, "getUniform",
4036 "unhandled type, WEBGL_video_texture extension not enabled");
4037 return ScriptValue::CreateNull(script_state->GetIsolate());
4038 }
4039 base_type = GL_INT;
4040 length = 1;
4041 break;
4042 default:
4043 if (!IsWebGL2()) {
4044 // Can't handle this type
4045 SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
4046 "unhandled type");
4047 return ScriptValue::CreateNull(script_state->GetIsolate());
4048 }
4049 // handle GLenums for WebGL 2.0 or higher
4050 switch (type) {
4051 case GL_UNSIGNED_INT:
4052 base_type = GL_UNSIGNED_INT;
4053 length = 1;
4054 break;
4055 case GL_UNSIGNED_INT_VEC2:
4056 base_type = GL_UNSIGNED_INT;
4057 length = 2;
4058 break;
4059 case GL_UNSIGNED_INT_VEC3:
4060 base_type = GL_UNSIGNED_INT;
4061 length = 3;
4062 break;
4063 case GL_UNSIGNED_INT_VEC4:
4064 base_type = GL_UNSIGNED_INT;
4065 length = 4;
4066 break;
4067 case GL_FLOAT_MAT2x3:
4068 base_type = GL_FLOAT;
4069 length = 6;
4070 break;
4071 case GL_FLOAT_MAT2x4:
4072 base_type = GL_FLOAT;
4073 length = 8;
4074 break;
4075 case GL_FLOAT_MAT3x2:
4076 base_type = GL_FLOAT;
4077 length = 6;
4078 break;
4079 case GL_FLOAT_MAT3x4:
4080 base_type = GL_FLOAT;
4081 length = 12;
4082 break;
4083 case GL_FLOAT_MAT4x2:
4084 base_type = GL_FLOAT;
4085 length = 8;
4086 break;
4087 case GL_FLOAT_MAT4x3:
4088 base_type = GL_FLOAT;
4089 length = 12;
4090 break;
4091 case GL_SAMPLER_3D:
4092 case GL_SAMPLER_2D_ARRAY:
4093 case GL_SAMPLER_2D_SHADOW:
4094 case GL_SAMPLER_CUBE_SHADOW:
4095 case GL_SAMPLER_2D_ARRAY_SHADOW:
4096 case GL_INT_SAMPLER_2D:
4097 case GL_INT_SAMPLER_CUBE:
4098 case GL_INT_SAMPLER_3D:
4099 case GL_INT_SAMPLER_2D_ARRAY:
4100 case GL_UNSIGNED_INT_SAMPLER_2D:
4101 case GL_UNSIGNED_INT_SAMPLER_CUBE:
4102 case GL_UNSIGNED_INT_SAMPLER_3D:
4103 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
4104 base_type = GL_INT;
4105 length = 1;
4106 break;
4107 default:
4108 // Can't handle this type
4109 SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
4110 "unhandled type");
4111 return ScriptValue::CreateNull(script_state->GetIsolate());
4112 }
4113 }
4114 switch (base_type) {
4115 case GL_FLOAT: {
4116 GLfloat value[16] = {0};
4117 ContextGL()->GetUniformfv(ObjectOrZero(program), location, value);
4118 if (length == 1)
4119 return WebGLAny(script_state, value[0]);
4120 return WebGLAny(script_state,
4121 DOMFloat32Array::Create(value, length));
4122 }
4123 case GL_INT: {
4124 GLint value[4] = {0};
4125 ContextGL()->GetUniformiv(ObjectOrZero(program), location, value);
4126 if (length == 1)
4127 return WebGLAny(script_state, value[0]);
4128 return WebGLAny(script_state, DOMInt32Array::Create(value, length));
4129 }
4130 case GL_UNSIGNED_INT: {
4131 GLuint value[4] = {0};
4132 ContextGL()->GetUniformuiv(ObjectOrZero(program), location, value);
4133 if (length == 1)
4134 return WebGLAny(script_state, value[0]);
4135 return WebGLAny(script_state,
4136 DOMUint32Array::Create(value, length));
4137 }
4138 case GL_BOOL: {
4139 GLint value[4] = {0};
4140 ContextGL()->GetUniformiv(ObjectOrZero(program), location, value);
4141 if (length > 1) {
4142 bool bool_value[4] = {0};
4143 for (unsigned j = 0; j < length; j++)
4144 bool_value[j] = static_cast<bool>(value[j]);
4145 return WebGLAny(script_state, bool_value, length);
4146 }
4147 return WebGLAny(script_state, static_cast<bool>(value[0]));
4148 }
4149 default:
4150 NOTIMPLEMENTED();
4151 }
4152 }
4153 }
4154 }
4155 // If we get here, something went wrong in our unfortunately complex logic
4156 // above
4157 SynthesizeGLError(GL_INVALID_VALUE, "getUniform", "unknown error");
4158 return ScriptValue::CreateNull(script_state->GetIsolate());
4159 }
4160
getUniformLocation(WebGLProgram * program,const String & name)4161 WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation(
4162 WebGLProgram* program,
4163 const String& name) {
4164 if (!ValidateWebGLProgramOrShader("getUniformLocation", program))
4165 return nullptr;
4166 if (!ValidateLocationLength("getUniformLocation", name))
4167 return nullptr;
4168 if (!ValidateString("getUniformLocation", name))
4169 return nullptr;
4170 if (IsPrefixReserved(name))
4171 return nullptr;
4172 if (!program->LinkStatus(this)) {
4173 SynthesizeGLError(GL_INVALID_OPERATION, "getUniformLocation",
4174 "program not linked");
4175 return nullptr;
4176 }
4177 GLint uniform_location = ContextGL()->GetUniformLocation(
4178 ObjectOrZero(program), name.Utf8().c_str());
4179 if (uniform_location == -1)
4180 return nullptr;
4181 return MakeGarbageCollected<WebGLUniformLocation>(program, uniform_location);
4182 }
4183
getVertexAttrib(ScriptState * script_state,GLuint index,GLenum pname)4184 ScriptValue WebGLRenderingContextBase::getVertexAttrib(
4185 ScriptState* script_state,
4186 GLuint index,
4187 GLenum pname) {
4188 if (isContextLost())
4189 return ScriptValue::CreateNull(script_state->GetIsolate());
4190 if (index >= max_vertex_attribs_) {
4191 SynthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib",
4192 "index out of range");
4193 return ScriptValue::CreateNull(script_state->GetIsolate());
4194 }
4195
4196 if ((ExtensionEnabled(kANGLEInstancedArraysName) || IsWebGL2()) &&
4197 pname == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE) {
4198 GLint value = 0;
4199 ContextGL()->GetVertexAttribiv(index, pname, &value);
4200 return WebGLAny(script_state, value);
4201 }
4202
4203 switch (pname) {
4204 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
4205 return WebGLAny(
4206 script_state,
4207 bound_vertex_array_object_->GetArrayBufferForAttrib(index));
4208 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
4209 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: {
4210 GLint value = 0;
4211 ContextGL()->GetVertexAttribiv(index, pname, &value);
4212 return WebGLAny(script_state, static_cast<bool>(value));
4213 }
4214 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
4215 case GL_VERTEX_ATTRIB_ARRAY_STRIDE: {
4216 GLint value = 0;
4217 ContextGL()->GetVertexAttribiv(index, pname, &value);
4218 return WebGLAny(script_state, value);
4219 }
4220 case GL_VERTEX_ATTRIB_ARRAY_TYPE: {
4221 GLint value = 0;
4222 ContextGL()->GetVertexAttribiv(index, pname, &value);
4223 return WebGLAny(script_state, static_cast<GLenum>(value));
4224 }
4225 case GL_CURRENT_VERTEX_ATTRIB: {
4226 switch (vertex_attrib_type_[index]) {
4227 case kFloat32ArrayType: {
4228 GLfloat float_value[4];
4229 ContextGL()->GetVertexAttribfv(index, pname, float_value);
4230 return WebGLAny(script_state,
4231 DOMFloat32Array::Create(float_value, 4));
4232 }
4233 case kInt32ArrayType: {
4234 GLint int_value[4];
4235 ContextGL()->GetVertexAttribIiv(index, pname, int_value);
4236 return WebGLAny(script_state, DOMInt32Array::Create(int_value, 4));
4237 }
4238 case kUint32ArrayType: {
4239 GLuint uint_value[4];
4240 ContextGL()->GetVertexAttribIuiv(index, pname, uint_value);
4241 return WebGLAny(script_state, DOMUint32Array::Create(uint_value, 4));
4242 }
4243 default:
4244 NOTREACHED();
4245 break;
4246 }
4247 return ScriptValue::CreateNull(script_state->GetIsolate());
4248 }
4249 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
4250 if (IsWebGL2()) {
4251 GLint value = 0;
4252 ContextGL()->GetVertexAttribiv(index, pname, &value);
4253 return WebGLAny(script_state, static_cast<bool>(value));
4254 }
4255 FALLTHROUGH;
4256 default:
4257 SynthesizeGLError(GL_INVALID_ENUM, "getVertexAttrib",
4258 "invalid parameter name");
4259 return ScriptValue::CreateNull(script_state->GetIsolate());
4260 }
4261 }
4262
getVertexAttribOffset(GLuint index,GLenum pname)4263 int64_t WebGLRenderingContextBase::getVertexAttribOffset(GLuint index,
4264 GLenum pname) {
4265 if (isContextLost())
4266 return 0;
4267 GLvoid* result = nullptr;
4268 // NOTE: If pname is ever a value that returns more than 1 element
4269 // this will corrupt memory.
4270 ContextGL()->GetVertexAttribPointerv(index, pname, &result);
4271 return static_cast<int64_t>(reinterpret_cast<intptr_t>(result));
4272 }
4273
hint(GLenum target,GLenum mode)4274 void WebGLRenderingContextBase::hint(GLenum target, GLenum mode) {
4275 if (isContextLost())
4276 return;
4277 bool is_valid = false;
4278 switch (target) {
4279 case GL_GENERATE_MIPMAP_HINT:
4280 is_valid = true;
4281 break;
4282 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
4283 if (ExtensionEnabled(kOESStandardDerivativesName) || IsWebGL2())
4284 is_valid = true;
4285 break;
4286 }
4287 if (!is_valid) {
4288 SynthesizeGLError(GL_INVALID_ENUM, "hint", "invalid target");
4289 return;
4290 }
4291 ContextGL()->Hint(target, mode);
4292 }
4293
isBuffer(WebGLBuffer * buffer)4294 GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer) {
4295 if (!buffer || isContextLost() || !buffer->Validate(ContextGroup(), this))
4296 return 0;
4297
4298 if (!buffer->HasEverBeenBound())
4299 return 0;
4300 if (buffer->MarkedForDeletion())
4301 return 0;
4302
4303 return ContextGL()->IsBuffer(buffer->Object());
4304 }
4305
isContextLost() const4306 bool WebGLRenderingContextBase::isContextLost() const {
4307 return context_lost_mode_ != kNotLostContext;
4308 }
4309
isEnabled(GLenum cap)4310 GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap) {
4311 if (isContextLost() || !ValidateCapability("isEnabled", cap))
4312 return 0;
4313 if (cap == GL_STENCIL_TEST)
4314 return stencil_enabled_;
4315 return ContextGL()->IsEnabled(cap);
4316 }
4317
isFramebuffer(WebGLFramebuffer * framebuffer)4318 GLboolean WebGLRenderingContextBase::isFramebuffer(
4319 WebGLFramebuffer* framebuffer) {
4320 if (!framebuffer || isContextLost() ||
4321 !framebuffer->Validate(ContextGroup(), this))
4322 return 0;
4323
4324 if (!framebuffer->HasEverBeenBound())
4325 return 0;
4326 if (framebuffer->MarkedForDeletion())
4327 return 0;
4328
4329 return ContextGL()->IsFramebuffer(framebuffer->Object());
4330 }
4331
isProgram(WebGLProgram * program)4332 GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program) {
4333 if (!program || isContextLost() || !program->Validate(ContextGroup(), this))
4334 return 0;
4335
4336 // OpenGL ES special-cases the behavior of program objects; if they're deleted
4337 // while attached to the current context state, glIsProgram is supposed to
4338 // still return true. For this reason, MarkedForDeletion is not checked here.
4339
4340 return ContextGL()->IsProgram(program->Object());
4341 }
4342
isRenderbuffer(WebGLRenderbuffer * renderbuffer)4343 GLboolean WebGLRenderingContextBase::isRenderbuffer(
4344 WebGLRenderbuffer* renderbuffer) {
4345 if (!renderbuffer || isContextLost() ||
4346 !renderbuffer->Validate(ContextGroup(), this))
4347 return 0;
4348
4349 if (!renderbuffer->HasEverBeenBound())
4350 return 0;
4351 if (renderbuffer->MarkedForDeletion())
4352 return 0;
4353
4354 return ContextGL()->IsRenderbuffer(renderbuffer->Object());
4355 }
4356
isShader(WebGLShader * shader)4357 GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader) {
4358 if (!shader || isContextLost() || !shader->Validate(ContextGroup(), this))
4359 return 0;
4360
4361 // OpenGL ES special-cases the behavior of shader objects; if they're deleted
4362 // while attached to a program, glIsShader is supposed to still return true.
4363 // For this reason, MarkedForDeletion is not checked here.
4364
4365 return ContextGL()->IsShader(shader->Object());
4366 }
4367
isTexture(WebGLTexture * texture)4368 GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture) {
4369 if (!texture || isContextLost() || !texture->Validate(ContextGroup(), this))
4370 return 0;
4371
4372 if (!texture->HasEverBeenBound())
4373 return 0;
4374 if (texture->MarkedForDeletion())
4375 return 0;
4376
4377 return ContextGL()->IsTexture(texture->Object());
4378 }
4379
lineWidth(GLfloat width)4380 void WebGLRenderingContextBase::lineWidth(GLfloat width) {
4381 if (isContextLost())
4382 return;
4383 ContextGL()->LineWidth(width);
4384 }
4385
linkProgram(WebGLProgram * program)4386 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program) {
4387 if (!ValidateWebGLProgramOrShader("linkProgram", program))
4388 return;
4389
4390 if (program->ActiveTransformFeedbackCount() > 0) {
4391 SynthesizeGLError(
4392 GL_INVALID_OPERATION, "linkProgram",
4393 "program being used by one or more active transform feedback objects");
4394 return;
4395 }
4396
4397 GLuint query = 0u;
4398 if (ExtensionEnabled(kKHRParallelShaderCompileName)) {
4399 ContextGL()->GenQueriesEXT(1, &query);
4400 ContextGL()->BeginQueryEXT(GL_PROGRAM_COMPLETION_QUERY_CHROMIUM, query);
4401 }
4402 ContextGL()->LinkProgram(ObjectOrZero(program));
4403 if (ExtensionEnabled(kKHRParallelShaderCompileName)) {
4404 ContextGL()->EndQueryEXT(GL_PROGRAM_COMPLETION_QUERY_CHROMIUM);
4405 addProgramCompletionQuery(program, query);
4406 }
4407
4408 program->IncreaseLinkCount();
4409 }
4410
pixelStorei(GLenum pname,GLint param)4411 void WebGLRenderingContextBase::pixelStorei(GLenum pname, GLint param) {
4412 if (isContextLost())
4413 return;
4414 switch (pname) {
4415 case GC3D_UNPACK_FLIP_Y_WEBGL:
4416 unpack_flip_y_ = param;
4417 break;
4418 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
4419 unpack_premultiply_alpha_ = param;
4420 break;
4421 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
4422 if (static_cast<GLenum>(param) == GC3D_BROWSER_DEFAULT_WEBGL ||
4423 param == GL_NONE) {
4424 unpack_colorspace_conversion_ = static_cast<GLenum>(param);
4425 } else {
4426 SynthesizeGLError(
4427 GL_INVALID_VALUE, "pixelStorei",
4428 "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
4429 return;
4430 }
4431 break;
4432 case GL_PACK_ALIGNMENT:
4433 case GL_UNPACK_ALIGNMENT:
4434 if (param == 1 || param == 2 || param == 4 || param == 8) {
4435 if (pname == GL_PACK_ALIGNMENT) {
4436 pack_alignment_ = param;
4437 } else { // GL_UNPACK_ALIGNMENT:
4438 unpack_alignment_ = param;
4439 }
4440 ContextGL()->PixelStorei(pname, param);
4441 } else {
4442 SynthesizeGLError(GL_INVALID_VALUE, "pixelStorei",
4443 "invalid parameter for alignment");
4444 return;
4445 }
4446 break;
4447 default:
4448 SynthesizeGLError(GL_INVALID_ENUM, "pixelStorei",
4449 "invalid parameter name");
4450 return;
4451 }
4452 }
4453
polygonOffset(GLfloat factor,GLfloat units)4454 void WebGLRenderingContextBase::polygonOffset(GLfloat factor, GLfloat units) {
4455 if (isContextLost())
4456 return;
4457 ContextGL()->PolygonOffset(factor, units);
4458 }
4459
ValidateReadBufferAndGetInfo(const char * function_name,WebGLFramebuffer * & read_framebuffer_binding)4460 bool WebGLRenderingContextBase::ValidateReadBufferAndGetInfo(
4461 const char* function_name,
4462 WebGLFramebuffer*& read_framebuffer_binding) {
4463 read_framebuffer_binding = GetReadFramebufferBinding();
4464 if (read_framebuffer_binding) {
4465 const char* reason = "framebuffer incomplete";
4466 if (read_framebuffer_binding->CheckDepthStencilStatus(&reason) !=
4467 GL_FRAMEBUFFER_COMPLETE) {
4468 SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, function_name,
4469 reason);
4470 return false;
4471 }
4472 } else {
4473 if (read_buffer_of_default_framebuffer_ == GL_NONE) {
4474 DCHECK(IsWebGL2());
4475 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
4476 "no image to read from");
4477 return false;
4478 }
4479 }
4480 return true;
4481 }
4482
ValidateReadPixelsFormatAndType(GLenum format,GLenum type,DOMArrayBufferView * buffer)4483 bool WebGLRenderingContextBase::ValidateReadPixelsFormatAndType(
4484 GLenum format,
4485 GLenum type,
4486 DOMArrayBufferView* buffer) {
4487 switch (format) {
4488 case GL_ALPHA:
4489 case GL_RGB:
4490 case GL_RGBA:
4491 break;
4492 default:
4493 SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid format");
4494 return false;
4495 }
4496
4497 switch (type) {
4498 case GL_UNSIGNED_BYTE:
4499 if (buffer) {
4500 auto bufferType = buffer->GetType();
4501 if (bufferType != DOMArrayBufferView::kTypeUint8 &&
4502 bufferType != DOMArrayBufferView::kTypeUint8Clamped) {
4503 SynthesizeGLError(
4504 GL_INVALID_OPERATION, "readPixels",
4505 "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array or "
4506 "Uint8ClampedArray");
4507 return false;
4508 }
4509 }
4510 return true;
4511 case GL_UNSIGNED_SHORT_5_6_5:
4512 case GL_UNSIGNED_SHORT_4_4_4_4:
4513 case GL_UNSIGNED_SHORT_5_5_5_1:
4514 if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeUint16) {
4515 SynthesizeGLError(
4516 GL_INVALID_OPERATION, "readPixels",
4517 "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
4518 return false;
4519 }
4520 return true;
4521 case GL_FLOAT:
4522 if (ExtensionEnabled(kOESTextureFloatName) ||
4523 ExtensionEnabled(kOESTextureHalfFloatName)) {
4524 if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeFloat32) {
4525 SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
4526 "type FLOAT but ArrayBufferView not Float32Array");
4527 return false;
4528 }
4529 return true;
4530 }
4531 SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
4532 return false;
4533 case GL_HALF_FLOAT_OES:
4534 if (ExtensionEnabled(kOESTextureHalfFloatName)) {
4535 if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeUint16) {
4536 SynthesizeGLError(
4537 GL_INVALID_OPERATION, "readPixels",
4538 "type HALF_FLOAT_OES but ArrayBufferView not Uint16Array");
4539 return false;
4540 }
4541 return true;
4542 }
4543 SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
4544 return false;
4545 default:
4546 SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
4547 return false;
4548 }
4549 }
4550
4551 WebGLImageConversion::PixelStoreParams
GetPackPixelStoreParams()4552 WebGLRenderingContextBase::GetPackPixelStoreParams() {
4553 WebGLImageConversion::PixelStoreParams params;
4554 params.alignment = pack_alignment_;
4555 return params;
4556 }
4557
4558 WebGLImageConversion::PixelStoreParams
GetUnpackPixelStoreParams(TexImageDimension)4559 WebGLRenderingContextBase::GetUnpackPixelStoreParams(TexImageDimension) {
4560 WebGLImageConversion::PixelStoreParams params;
4561 params.alignment = unpack_alignment_;
4562 return params;
4563 }
4564
ValidateReadPixelsFuncParameters(GLsizei width,GLsizei height,GLenum format,GLenum type,DOMArrayBufferView * buffer,int64_t buffer_size)4565 bool WebGLRenderingContextBase::ValidateReadPixelsFuncParameters(
4566 GLsizei width,
4567 GLsizei height,
4568 GLenum format,
4569 GLenum type,
4570 DOMArrayBufferView* buffer,
4571 int64_t buffer_size) {
4572 if (!ValidateReadPixelsFormatAndType(format, type, buffer))
4573 return false;
4574
4575 // Calculate array size, taking into consideration of pack parameters.
4576 unsigned total_bytes_required = 0, total_skip_bytes = 0;
4577 GLenum error = WebGLImageConversion::ComputeImageSizeInBytes(
4578 format, type, width, height, 1, GetPackPixelStoreParams(),
4579 &total_bytes_required, nullptr, &total_skip_bytes);
4580 if (error != GL_NO_ERROR) {
4581 SynthesizeGLError(error, "readPixels", "invalid dimensions");
4582 return false;
4583 }
4584 if (buffer_size <
4585 static_cast<int64_t>(total_bytes_required + total_skip_bytes)) {
4586 SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
4587 "buffer is not large enough for dimensions");
4588 return false;
4589 }
4590 return true;
4591 }
4592
readPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,MaybeShared<DOMArrayBufferView> pixels)4593 void WebGLRenderingContextBase::readPixels(
4594 GLint x,
4595 GLint y,
4596 GLsizei width,
4597 GLsizei height,
4598 GLenum format,
4599 GLenum type,
4600 MaybeShared<DOMArrayBufferView> pixels) {
4601 if (IdentifiabilityStudySettings::Get()->ShouldSample(
4602 blink::IdentifiableSurface::Type::kCanvasReadback)) {
4603 const auto& ukm_params = GetUkmParameters();
4604 blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
4605 .Set(blink::IdentifiableSurface::FromTypeAndToken(
4606 blink::IdentifiableSurface::Type::kCanvasReadback,
4607 GetContextType()),
4608 0)
4609 .Record(ukm_params.ukm_recorder);
4610 }
4611 ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), 0);
4612 }
4613
ReadPixelsHelper(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,DOMArrayBufferView * pixels,int64_t offset)4614 void WebGLRenderingContextBase::ReadPixelsHelper(GLint x,
4615 GLint y,
4616 GLsizei width,
4617 GLsizei height,
4618 GLenum format,
4619 GLenum type,
4620 DOMArrayBufferView* pixels,
4621 int64_t offset) {
4622 if (isContextLost())
4623 return;
4624 // Due to WebGL's same-origin restrictions, it is not possible to
4625 // taint the origin using the WebGL API.
4626 DCHECK(Host()->OriginClean());
4627
4628 // Validate input parameters.
4629 if (!pixels) {
4630 SynthesizeGLError(GL_INVALID_VALUE, "readPixels",
4631 "no destination ArrayBufferView");
4632 return;
4633 }
4634 base::CheckedNumeric<GLuint> offset_in_bytes = offset;
4635 offset_in_bytes *= pixels->TypeSize();
4636 if (!offset_in_bytes.IsValid() ||
4637 static_cast<size_t>(offset_in_bytes.ValueOrDie()) >
4638 pixels->byteLength()) {
4639 SynthesizeGLError(GL_INVALID_VALUE, "readPixels",
4640 "destination offset out of range");
4641 return;
4642 }
4643 const char* reason = "framebuffer incomplete";
4644 WebGLFramebuffer* framebuffer = GetReadFramebufferBinding();
4645 if (framebuffer && framebuffer->CheckDepthStencilStatus(&reason) !=
4646 GL_FRAMEBUFFER_COMPLETE) {
4647 SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
4648 return;
4649 }
4650 base::CheckedNumeric<GLuint> buffer_size =
4651 pixels->byteLength() - offset_in_bytes;
4652 if (!buffer_size.IsValid()) {
4653 SynthesizeGLError(GL_INVALID_VALUE, "readPixels",
4654 "destination offset out of range");
4655 return;
4656 }
4657 if (!ValidateReadPixelsFuncParameters(width, height, format, type, pixels,
4658 buffer_size.ValueOrDie())) {
4659 return;
4660 }
4661 ClearIfComposited();
4662
4663 uint8_t* data = static_cast<uint8_t*>(pixels->BaseAddressMaybeShared()) +
4664 offset_in_bytes.ValueOrDie();
4665
4666 // We add special handling here if the 'ArrayBufferView' is size '0' and the
4667 // backing store is 'nullptr'. 'ReadPixels' creates an error if the provided
4668 // data is 'nullptr'. However, in the case that we want to read zero pixels,
4669 // we want to avoid this error. Therefore we provide temporary memory here if
4670 // 'ArrayBufferView' does not provide a backing store but we actually read
4671 // zero pixels.
4672 base::Optional<Vector<uint8_t>> buffer;
4673 if (!data && (width == 0 || height == 0)) {
4674 buffer.emplace(32);
4675 data = buffer->data();
4676 }
4677 {
4678 ScopedDrawingBufferBinder binder(GetDrawingBuffer(), framebuffer);
4679 ContextGL()->ReadPixels(x, y, width, height, format, type, data);
4680 }
4681 }
4682
RenderbufferStorageImpl(GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,const char * function_name)4683 void WebGLRenderingContextBase::RenderbufferStorageImpl(
4684 GLenum target,
4685 GLsizei samples,
4686 GLenum internalformat,
4687 GLsizei width,
4688 GLsizei height,
4689 const char* function_name) {
4690 DCHECK(!samples); // |samples| > 0 is only valid in WebGL2's
4691 // renderbufferStorageMultisample().
4692 DCHECK(!IsWebGL2()); // Make sure this is overridden in WebGL 2.
4693 switch (internalformat) {
4694 case GL_DEPTH_COMPONENT16:
4695 case GL_RGBA4:
4696 case GL_RGB5_A1:
4697 case GL_RGB565:
4698 case GL_STENCIL_INDEX8:
4699 ContextGL()->RenderbufferStorage(target, internalformat, width, height);
4700 renderbuffer_binding_->SetInternalFormat(internalformat);
4701 renderbuffer_binding_->SetSize(width, height);
4702 break;
4703 case GL_SRGB8_ALPHA8_EXT:
4704 if (!ExtensionEnabled(kEXTsRGBName)) {
4705 SynthesizeGLError(GL_INVALID_ENUM, function_name, "sRGB not enabled");
4706 break;
4707 }
4708 ContextGL()->RenderbufferStorage(target, internalformat, width, height);
4709 renderbuffer_binding_->SetInternalFormat(internalformat);
4710 renderbuffer_binding_->SetSize(width, height);
4711 break;
4712 case GL_DEPTH_STENCIL_OES:
4713 DCHECK(IsDepthStencilSupported());
4714 ContextGL()->RenderbufferStorage(target, GL_DEPTH24_STENCIL8_OES, width,
4715 height);
4716 renderbuffer_binding_->SetSize(width, height);
4717 renderbuffer_binding_->SetInternalFormat(internalformat);
4718 break;
4719 default:
4720 SynthesizeGLError(GL_INVALID_ENUM, function_name,
4721 "invalid internalformat");
4722 break;
4723 }
4724 UpdateNumberOfUserAllocatedMultisampledRenderbuffers(
4725 renderbuffer_binding_->UpdateMultisampleState(false));
4726 }
4727
renderbufferStorage(GLenum target,GLenum internalformat,GLsizei width,GLsizei height)4728 void WebGLRenderingContextBase::renderbufferStorage(GLenum target,
4729 GLenum internalformat,
4730 GLsizei width,
4731 GLsizei height) {
4732 const char* function_name = "renderbufferStorage";
4733 if (isContextLost())
4734 return;
4735 if (target != GL_RENDERBUFFER) {
4736 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
4737 return;
4738 }
4739 if (!renderbuffer_binding_ || !renderbuffer_binding_->Object()) {
4740 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
4741 "no bound renderbuffer");
4742 return;
4743 }
4744 if (!ValidateSize(function_name, width, height))
4745 return;
4746 RenderbufferStorageImpl(target, 0, internalformat, width, height,
4747 function_name);
4748 ApplyStencilTest();
4749 }
4750
sampleCoverage(GLfloat value,GLboolean invert)4751 void WebGLRenderingContextBase::sampleCoverage(GLfloat value,
4752 GLboolean invert) {
4753 if (isContextLost())
4754 return;
4755 ContextGL()->SampleCoverage(value, invert);
4756 }
4757
scissor(GLint x,GLint y,GLsizei width,GLsizei height)4758 void WebGLRenderingContextBase::scissor(GLint x,
4759 GLint y,
4760 GLsizei width,
4761 GLsizei height) {
4762 if (isContextLost())
4763 return;
4764 scissor_box_[0] = x;
4765 scissor_box_[1] = y;
4766 scissor_box_[2] = width;
4767 scissor_box_[3] = height;
4768 ContextGL()->Scissor(x, y, width, height);
4769 }
4770
shaderSource(WebGLShader * shader,const String & string)4771 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader,
4772 const String& string) {
4773 if (!ValidateWebGLProgramOrShader("shaderSource", shader))
4774 return;
4775 String string_without_comments = StripComments(string).Result();
4776 shader->SetSource(string);
4777 if (!string_without_comments.Is8Bit() ||
4778 !string_without_comments.ContainsOnlyASCIIOrEmpty()) {
4779 SynthesizeGLError(
4780 GL_INVALID_VALUE, "shaderSource",
4781 "Non ASCII character detected after comments are stripped.");
4782 return;
4783 }
4784 const GLchar* shader_data =
4785 reinterpret_cast<const GLchar*>(string_without_comments.Characters8());
4786 const GLint shader_length = string_without_comments.length();
4787 ContextGL()->ShaderSource(ObjectOrZero(shader), 1, &shader_data,
4788 &shader_length);
4789 }
4790
stencilFunc(GLenum func,GLint ref,GLuint mask)4791 void WebGLRenderingContextBase::stencilFunc(GLenum func,
4792 GLint ref,
4793 GLuint mask) {
4794 if (isContextLost())
4795 return;
4796 if (!ValidateStencilOrDepthFunc("stencilFunc", func))
4797 return;
4798 stencil_func_ref_ = ref;
4799 stencil_func_ref_back_ = ref;
4800 stencil_func_mask_ = mask;
4801 stencil_func_mask_back_ = mask;
4802 ContextGL()->StencilFunc(func, ref, mask);
4803 }
4804
stencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask)4805 void WebGLRenderingContextBase::stencilFuncSeparate(GLenum face,
4806 GLenum func,
4807 GLint ref,
4808 GLuint mask) {
4809 if (isContextLost())
4810 return;
4811 if (!ValidateStencilOrDepthFunc("stencilFuncSeparate", func))
4812 return;
4813 switch (face) {
4814 case GL_FRONT_AND_BACK:
4815 stencil_func_ref_ = ref;
4816 stencil_func_ref_back_ = ref;
4817 stencil_func_mask_ = mask;
4818 stencil_func_mask_back_ = mask;
4819 break;
4820 case GL_FRONT:
4821 stencil_func_ref_ = ref;
4822 stencil_func_mask_ = mask;
4823 break;
4824 case GL_BACK:
4825 stencil_func_ref_back_ = ref;
4826 stencil_func_mask_back_ = mask;
4827 break;
4828 default:
4829 SynthesizeGLError(GL_INVALID_ENUM, "stencilFuncSeparate", "invalid face");
4830 return;
4831 }
4832 ContextGL()->StencilFuncSeparate(face, func, ref, mask);
4833 }
4834
stencilMask(GLuint mask)4835 void WebGLRenderingContextBase::stencilMask(GLuint mask) {
4836 if (isContextLost())
4837 return;
4838 stencil_mask_ = mask;
4839 stencil_mask_back_ = mask;
4840 ContextGL()->StencilMask(mask);
4841 }
4842
stencilMaskSeparate(GLenum face,GLuint mask)4843 void WebGLRenderingContextBase::stencilMaskSeparate(GLenum face, GLuint mask) {
4844 if (isContextLost())
4845 return;
4846 switch (face) {
4847 case GL_FRONT_AND_BACK:
4848 stencil_mask_ = mask;
4849 stencil_mask_back_ = mask;
4850 break;
4851 case GL_FRONT:
4852 stencil_mask_ = mask;
4853 break;
4854 case GL_BACK:
4855 stencil_mask_back_ = mask;
4856 break;
4857 default:
4858 SynthesizeGLError(GL_INVALID_ENUM, "stencilMaskSeparate", "invalid face");
4859 return;
4860 }
4861 ContextGL()->StencilMaskSeparate(face, mask);
4862 }
4863
stencilOp(GLenum fail,GLenum zfail,GLenum zpass)4864 void WebGLRenderingContextBase::stencilOp(GLenum fail,
4865 GLenum zfail,
4866 GLenum zpass) {
4867 if (isContextLost())
4868 return;
4869 ContextGL()->StencilOp(fail, zfail, zpass);
4870 }
4871
stencilOpSeparate(GLenum face,GLenum fail,GLenum zfail,GLenum zpass)4872 void WebGLRenderingContextBase::stencilOpSeparate(GLenum face,
4873 GLenum fail,
4874 GLenum zfail,
4875 GLenum zpass) {
4876 if (isContextLost())
4877 return;
4878 ContextGL()->StencilOpSeparate(face, fail, zfail, zpass);
4879 }
4880
ConvertTexInternalFormat(GLenum internalformat,GLenum type)4881 GLenum WebGLRenderingContextBase::ConvertTexInternalFormat(
4882 GLenum internalformat,
4883 GLenum type) {
4884 // Convert to sized internal formats that are renderable with
4885 // GL_CHROMIUM_color_buffer_float_rgb(a).
4886 if (type == GL_FLOAT && internalformat == GL_RGBA &&
4887 ExtensionsUtil()->IsExtensionEnabled(
4888 "GL_CHROMIUM_color_buffer_float_rgba"))
4889 return GL_RGBA32F_EXT;
4890 if (type == GL_FLOAT && internalformat == GL_RGB &&
4891 ExtensionsUtil()->IsExtensionEnabled(
4892 "GL_CHROMIUM_color_buffer_float_rgb"))
4893 return GL_RGB32F_EXT;
4894 return internalformat;
4895 }
4896
TexImage2DBase(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)4897 void WebGLRenderingContextBase::TexImage2DBase(GLenum target,
4898 GLint level,
4899 GLint internalformat,
4900 GLsizei width,
4901 GLsizei height,
4902 GLint border,
4903 GLenum format,
4904 GLenum type,
4905 const void* pixels) {
4906 // All calling functions check isContextLost, so a duplicate check is not
4907 // needed here.
4908 ContextGL()->TexImage2D(target, level,
4909 ConvertTexInternalFormat(internalformat, type), width,
4910 height, border, format, type, pixels);
4911 }
4912
4913 // Software-based upload of Image* to WebGL texture.
TexImageImpl(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLint xoffset,GLint yoffset,GLint zoffset,GLenum format,GLenum type,Image * image,WebGLImageConversion::ImageHtmlDomSource dom_source,bool flip_y,bool premultiply_alpha,const IntRect & source_image_rect,GLsizei depth,GLint unpack_image_height)4914 void WebGLRenderingContextBase::TexImageImpl(
4915 TexImageFunctionID function_id,
4916 GLenum target,
4917 GLint level,
4918 GLint internalformat,
4919 GLint xoffset,
4920 GLint yoffset,
4921 GLint zoffset,
4922 GLenum format,
4923 GLenum type,
4924 Image* image,
4925 WebGLImageConversion::ImageHtmlDomSource dom_source,
4926 bool flip_y,
4927 bool premultiply_alpha,
4928 const IntRect& source_image_rect,
4929 GLsizei depth,
4930 GLint unpack_image_height) {
4931 const char* func_name = GetTexImageFunctionName(function_id);
4932 // All calling functions check isContextLost, so a duplicate check is not
4933 // needed here.
4934 if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
4935 // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
4936 type = GL_FLOAT;
4937 }
4938 Vector<uint8_t> data;
4939
4940 IntRect sub_rect = source_image_rect;
4941 if (sub_rect.IsValid() && sub_rect == SentinelEmptyRect()) {
4942 // Recalculate based on the size of the Image.
4943 sub_rect = SafeGetImageSize(image);
4944 }
4945
4946 bool selecting_sub_rectangle = false;
4947 if (!ValidateTexImageSubRectangle(func_name, function_id, image, sub_rect,
4948 depth, unpack_image_height,
4949 &selecting_sub_rectangle)) {
4950 return;
4951 }
4952
4953 // Adjust the source image rectangle if doing a y-flip.
4954 IntRect adjusted_source_image_rect = sub_rect;
4955 if (flip_y) {
4956 adjusted_source_image_rect.SetY(image->height() -
4957 adjusted_source_image_rect.MaxY());
4958 }
4959
4960 WebGLImageConversion::ImageExtractor image_extractor(
4961 image, dom_source, premultiply_alpha,
4962 unpack_colorspace_conversion_ == GL_NONE);
4963 if (!image_extractor.ImagePixelData()) {
4964 SynthesizeGLError(GL_INVALID_VALUE, func_name, "bad image data");
4965 return;
4966 }
4967
4968 WebGLImageConversion::DataFormat source_data_format =
4969 image_extractor.ImageSourceFormat();
4970 WebGLImageConversion::AlphaOp alpha_op = image_extractor.ImageAlphaOp();
4971 const void* image_pixel_data = image_extractor.ImagePixelData();
4972
4973 bool need_conversion = true;
4974 if (type == GL_UNSIGNED_BYTE &&
4975 source_data_format == WebGLImageConversion::kDataFormatRGBA8 &&
4976 format == GL_RGBA && alpha_op == WebGLImageConversion::kAlphaDoNothing &&
4977 !flip_y && !selecting_sub_rectangle && depth == 1) {
4978 need_conversion = false;
4979 } else {
4980 if (!WebGLImageConversion::PackImageData(
4981 image, image_pixel_data, format, type, flip_y, alpha_op,
4982 source_data_format, image_extractor.ImageWidth(),
4983 image_extractor.ImageHeight(), adjusted_source_image_rect, depth,
4984 image_extractor.ImageSourceUnpackAlignment(), unpack_image_height,
4985 data)) {
4986 SynthesizeGLError(GL_INVALID_VALUE, func_name, "packImage error");
4987 return;
4988 }
4989 }
4990
4991 ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
4992 if (function_id == kTexImage2D) {
4993 TexImage2DBase(target, level, internalformat,
4994 adjusted_source_image_rect.Width(),
4995 adjusted_source_image_rect.Height(), 0, format, type,
4996 need_conversion ? data.data() : image_pixel_data);
4997 } else if (function_id == kTexSubImage2D) {
4998 ContextGL()->TexSubImage2D(
4999 target, level, xoffset, yoffset, adjusted_source_image_rect.Width(),
5000 adjusted_source_image_rect.Height(), format, type,
5001 need_conversion ? data.data() : image_pixel_data);
5002 } else {
5003 // 3D functions.
5004 if (function_id == kTexImage3D) {
5005 ContextGL()->TexImage3D(
5006 target, level, internalformat, adjusted_source_image_rect.Width(),
5007 adjusted_source_image_rect.Height(), depth, 0, format, type,
5008 need_conversion ? data.data() : image_pixel_data);
5009 } else {
5010 DCHECK_EQ(function_id, kTexSubImage3D);
5011 ContextGL()->TexSubImage3D(
5012 target, level, xoffset, yoffset, zoffset,
5013 adjusted_source_image_rect.Width(),
5014 adjusted_source_image_rect.Height(), depth, format, type,
5015 need_conversion ? data.data() : image_pixel_data);
5016 }
5017 }
5018 }
5019
ValidateTexFunc(const char * function_name,TexImageFunctionType function_type,TexFuncValidationSourceType source_type,GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset)5020 bool WebGLRenderingContextBase::ValidateTexFunc(
5021 const char* function_name,
5022 TexImageFunctionType function_type,
5023 TexFuncValidationSourceType source_type,
5024 GLenum target,
5025 GLint level,
5026 GLenum internalformat,
5027 GLsizei width,
5028 GLsizei height,
5029 GLsizei depth,
5030 GLint border,
5031 GLenum format,
5032 GLenum type,
5033 GLint xoffset,
5034 GLint yoffset,
5035 GLint zoffset) {
5036 if (!ValidateTexFuncLevel(function_name, target, level))
5037 return false;
5038
5039 if (!ValidateTexFuncParameters(function_name, function_type, source_type,
5040 target, level, internalformat, width, height,
5041 depth, border, format, type))
5042 return false;
5043
5044 if (function_type == kTexSubImage) {
5045 if (!ValidateSettableTexFormat(function_name, format))
5046 return false;
5047 if (!ValidateSize(function_name, xoffset, yoffset, zoffset))
5048 return false;
5049 } else {
5050 // For SourceArrayBufferView, function validateTexFuncData() would handle
5051 // whether to validate the SettableTexFormat
5052 // by checking if the ArrayBufferView is null or not.
5053 if (source_type != kSourceArrayBufferView) {
5054 if (!ValidateSettableTexFormat(function_name, format))
5055 return false;
5056 }
5057 }
5058
5059 return true;
5060 }
5061
ValidateValueFitNonNegInt32(const char * function_name,const char * param_name,int64_t value)5062 bool WebGLRenderingContextBase::ValidateValueFitNonNegInt32(
5063 const char* function_name,
5064 const char* param_name,
5065 int64_t value) {
5066 if (value < 0) {
5067 String error_msg = String(param_name) + " < 0";
5068 SynthesizeGLError(GL_INVALID_VALUE, function_name,
5069 error_msg.Ascii().c_str());
5070 return false;
5071 }
5072 if (value > static_cast<int64_t>(std::numeric_limits<int>::max())) {
5073 String error_msg = String(param_name) + " more than 32-bit";
5074 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
5075 error_msg.Ascii().c_str());
5076 return false;
5077 }
5078 return true;
5079 }
5080
5081 // TODO(fmalita): figure why WebGLImageConversion::ImageExtractor can't handle
5082 // SVG-backed images, and get rid of this intermediate step.
DrawImageIntoBuffer(scoped_refptr<Image> pass_image,int width,int height,const char * function_name)5083 scoped_refptr<Image> WebGLRenderingContextBase::DrawImageIntoBuffer(
5084 scoped_refptr<Image> pass_image,
5085 int width,
5086 int height,
5087 const char* function_name) {
5088 scoped_refptr<Image> image(std::move(pass_image));
5089 DCHECK(image);
5090
5091 IntSize size(width, height);
5092 CanvasResourceProvider* resource_provider =
5093 generated_image_cache_.GetCanvasResourceProvider(size);
5094 if (!resource_provider) {
5095 SynthesizeGLError(GL_OUT_OF_MEMORY, function_name, "out of memory");
5096 return nullptr;
5097 }
5098
5099 if (!image->CurrentFrameKnownToBeOpaque())
5100 resource_provider->Canvas()->clear(SK_ColorTRANSPARENT);
5101
5102 IntRect src_rect(IntPoint(), image->Size());
5103 IntRect dest_rect(0, 0, size.Width(), size.Height());
5104 PaintFlags flags;
5105 // TODO(ccameron): WebGL should produce sRGB images.
5106 // https://crbug.com/672299
5107 image->Draw(resource_provider->Canvas(), flags, FloatRect(dest_rect),
5108 FloatRect(src_rect), kRespectImageOrientation,
5109 Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
5110 return resource_provider->Snapshot();
5111 }
5112
ValidateTexImageBinding(const char * func_name,TexImageFunctionID function_id,GLenum target)5113 WebGLTexture* WebGLRenderingContextBase::ValidateTexImageBinding(
5114 const char* func_name,
5115 TexImageFunctionID function_id,
5116 GLenum target) {
5117 return ValidateTexture2DBinding(func_name, target);
5118 }
5119
GetTexImageFunctionName(TexImageFunctionID func_name)5120 const char* WebGLRenderingContextBase::GetTexImageFunctionName(
5121 TexImageFunctionID func_name) {
5122 switch (func_name) {
5123 case kTexImage2D:
5124 return "texImage2D";
5125 case kTexSubImage2D:
5126 return "texSubImage2D";
5127 case kTexSubImage3D:
5128 return "texSubImage3D";
5129 case kTexImage3D:
5130 return "texImage3D";
5131 default: // Adding default to prevent compile error
5132 return "";
5133 }
5134 }
5135
SentinelEmptyRect()5136 IntRect WebGLRenderingContextBase::SentinelEmptyRect() {
5137 // Return a rectangle with -1 width and height so we can recognize
5138 // it later and recalculate it based on the Image whose data we'll
5139 // upload. It's important that there be no possible differences in
5140 // the logic which computes the image's size.
5141 return IntRect(0, 0, -1, -1);
5142 }
5143
SafeGetImageSize(Image * image)5144 IntRect WebGLRenderingContextBase::SafeGetImageSize(Image* image) {
5145 if (!image)
5146 return IntRect();
5147
5148 return GetTextureSourceSize(image);
5149 }
5150
GetImageDataSize(ImageData * pixels)5151 IntRect WebGLRenderingContextBase::GetImageDataSize(ImageData* pixels) {
5152 DCHECK(pixels);
5153 return GetTextureSourceSize(pixels);
5154 }
5155
TexImageHelperDOMArrayBufferView(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,DOMArrayBufferView * pixels,NullDisposition null_disposition,GLuint src_offset)5156 void WebGLRenderingContextBase::TexImageHelperDOMArrayBufferView(
5157 TexImageFunctionID function_id,
5158 GLenum target,
5159 GLint level,
5160 GLint internalformat,
5161 GLsizei width,
5162 GLsizei height,
5163 GLsizei depth,
5164 GLint border,
5165 GLenum format,
5166 GLenum type,
5167 GLint xoffset,
5168 GLint yoffset,
5169 GLint zoffset,
5170 DOMArrayBufferView* pixels,
5171 NullDisposition null_disposition,
5172 GLuint src_offset) {
5173 const char* func_name = GetTexImageFunctionName(function_id);
5174 if (isContextLost())
5175 return;
5176 if (!ValidateTexImageBinding(func_name, function_id, target))
5177 return;
5178 TexImageFunctionType function_type;
5179 if (function_id == kTexImage2D || function_id == kTexImage3D)
5180 function_type = kTexImage;
5181 else
5182 function_type = kTexSubImage;
5183 if (!ValidateTexFunc(func_name, function_type, kSourceArrayBufferView, target,
5184 level, internalformat, width, height, depth, border,
5185 format, type, xoffset, yoffset, zoffset))
5186 return;
5187 TexImageDimension source_type;
5188 if (function_id == kTexImage2D || function_id == kTexSubImage2D)
5189 source_type = kTex2D;
5190 else
5191 source_type = kTex3D;
5192 if (!ValidateTexFuncData(func_name, source_type, level, width, height, depth,
5193 format, type, pixels, null_disposition, src_offset))
5194 return;
5195 uint8_t* data = reinterpret_cast<uint8_t*>(
5196 pixels ? pixels->BaseAddressMaybeShared() : nullptr);
5197 if (src_offset) {
5198 DCHECK(pixels);
5199 // No need to check overflow because validateTexFuncData() already did.
5200 data += src_offset * pixels->TypeSize();
5201 }
5202 Vector<uint8_t> temp_data;
5203 bool change_unpack_params = false;
5204 if (data && width && height &&
5205 (unpack_flip_y_ || unpack_premultiply_alpha_)) {
5206 DCHECK_EQ(kTex2D, source_type);
5207 // Only enter here if width or height is non-zero. Otherwise, call to the
5208 // underlying driver to generate appropriate GL errors if needed.
5209 WebGLImageConversion::PixelStoreParams unpack_params =
5210 GetUnpackPixelStoreParams(kTex2D);
5211 GLint data_store_width =
5212 unpack_params.row_length ? unpack_params.row_length : width;
5213 if (unpack_params.skip_pixels + width > data_store_width) {
5214 SynthesizeGLError(GL_INVALID_OPERATION, func_name,
5215 "Invalid unpack params combination.");
5216 return;
5217 }
5218 if (!WebGLImageConversion::ExtractTextureData(
5219 width, height, format, type, unpack_params, unpack_flip_y_,
5220 unpack_premultiply_alpha_, data, temp_data)) {
5221 SynthesizeGLError(GL_INVALID_OPERATION, func_name,
5222 "Invalid format/type combination.");
5223 return;
5224 }
5225 data = temp_data.data();
5226 change_unpack_params = true;
5227 }
5228 if (function_id == kTexImage3D) {
5229 ContextGL()->TexImage3D(target, level,
5230 ConvertTexInternalFormat(internalformat, type),
5231 width, height, depth, border, format, type, data);
5232 return;
5233 }
5234 if (function_id == kTexSubImage3D) {
5235 ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
5236 height, depth, format, type, data);
5237 return;
5238 }
5239
5240 ScopedUnpackParametersResetRestore temporary_reset_unpack(
5241 this, change_unpack_params);
5242 if (function_id == kTexImage2D)
5243 TexImage2DBase(target, level, internalformat, width, height, border, format,
5244 type, data);
5245 else if (function_id == kTexSubImage2D)
5246 ContextGL()->TexSubImage2D(target, level, xoffset, yoffset, width, height,
5247 format, type, data);
5248 }
5249
texImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,MaybeShared<DOMArrayBufferView> pixels)5250 void WebGLRenderingContextBase::texImage2D(
5251 GLenum target,
5252 GLint level,
5253 GLint internalformat,
5254 GLsizei width,
5255 GLsizei height,
5256 GLint border,
5257 GLenum format,
5258 GLenum type,
5259 MaybeShared<DOMArrayBufferView> pixels) {
5260 TexImageHelperDOMArrayBufferView(kTexImage2D, target, level, internalformat,
5261 width, height, 1, border, format, type, 0, 0,
5262 0, pixels.View(), kNullAllowed, 0);
5263 }
5264
TexImageHelperImageData(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLint border,GLenum format,GLenum type,GLsizei depth,GLint xoffset,GLint yoffset,GLint zoffset,ImageData * pixels,const IntRect & source_image_rect,GLint unpack_image_height)5265 void WebGLRenderingContextBase::TexImageHelperImageData(
5266 TexImageFunctionID function_id,
5267 GLenum target,
5268 GLint level,
5269 GLint internalformat,
5270 GLint border,
5271 GLenum format,
5272 GLenum type,
5273 GLsizei depth,
5274 GLint xoffset,
5275 GLint yoffset,
5276 GLint zoffset,
5277 ImageData* pixels,
5278 const IntRect& source_image_rect,
5279 GLint unpack_image_height) {
5280 const char* func_name = GetTexImageFunctionName(function_id);
5281 if (isContextLost())
5282 return;
5283 DCHECK(pixels);
5284 DCHECK(!pixels->data().IsNull());
5285 if (pixels->BufferBase()->IsDetached()) {
5286 SynthesizeGLError(GL_INVALID_VALUE, func_name,
5287 "The source data has been detached.");
5288 return;
5289 }
5290
5291 if (!ValidateTexImageBinding(func_name, function_id, target))
5292 return;
5293 TexImageFunctionType function_type;
5294 if (function_id == kTexImage2D || function_id == kTexImage3D)
5295 function_type = kTexImage;
5296 else
5297 function_type = kTexSubImage;
5298 if (!ValidateTexFunc(func_name, function_type, kSourceImageData, target,
5299 level, internalformat, pixels->width(), pixels->height(),
5300 depth, border, format, type, xoffset, yoffset, zoffset))
5301 return;
5302
5303 bool selecting_sub_rectangle = false;
5304 if (!ValidateTexImageSubRectangle(
5305 func_name, function_id, pixels, source_image_rect, depth,
5306 unpack_image_height, &selecting_sub_rectangle)) {
5307 return;
5308 }
5309 // Adjust the source image rectangle if doing a y-flip.
5310 IntRect adjusted_source_image_rect = source_image_rect;
5311 if (unpack_flip_y_) {
5312 adjusted_source_image_rect.SetY(pixels->height() -
5313 adjusted_source_image_rect.MaxY());
5314 }
5315
5316 // TODO(crbug.com/1115317): Should be compatible with uint_8, float16 and
5317 // float32.
5318 Vector<uint8_t> data;
5319 bool need_conversion = true;
5320 // The data from ImageData is always of format RGBA8.
5321 // No conversion is needed if destination format is RGBA and type is
5322 // UNSIGNED_BYTE and no Flip or Premultiply operation is required.
5323 if (!unpack_flip_y_ && !unpack_premultiply_alpha_ && format == GL_RGBA &&
5324 type == GL_UNSIGNED_BYTE && !selecting_sub_rectangle && depth == 1) {
5325 need_conversion = false;
5326 } else {
5327 if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
5328 // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
5329 type = GL_FLOAT;
5330 }
5331 if (!WebGLImageConversion::ExtractImageData(
5332 pixels->data().GetAsUint8ClampedArray()->Data(),
5333 WebGLImageConversion::DataFormat::kDataFormatRGBA8, pixels->Size(),
5334 adjusted_source_image_rect, depth, unpack_image_height, format,
5335 type, unpack_flip_y_, unpack_premultiply_alpha_, data)) {
5336 SynthesizeGLError(GL_INVALID_VALUE, func_name, "bad image data");
5337 return;
5338 }
5339 }
5340 ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
5341 const uint8_t* bytes = need_conversion
5342 ? data.data()
5343 : pixels->data().GetAsUint8ClampedArray()->Data();
5344 if (function_id == kTexImage2D) {
5345 DCHECK_EQ(unpack_image_height, 0);
5346 TexImage2DBase(
5347 target, level, internalformat, adjusted_source_image_rect.Width(),
5348 adjusted_source_image_rect.Height(), border, format, type, bytes);
5349 } else if (function_id == kTexSubImage2D) {
5350 DCHECK_EQ(unpack_image_height, 0);
5351 ContextGL()->TexSubImage2D(
5352 target, level, xoffset, yoffset, adjusted_source_image_rect.Width(),
5353 adjusted_source_image_rect.Height(), format, type, bytes);
5354 } else {
5355 GLint upload_height = adjusted_source_image_rect.Height();
5356 if (function_id == kTexImage3D) {
5357 ContextGL()->TexImage3D(target, level, internalformat,
5358 adjusted_source_image_rect.Width(), upload_height,
5359 depth, border, format, type, bytes);
5360 } else {
5361 DCHECK_EQ(function_id, kTexSubImage3D);
5362 ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset,
5363 adjusted_source_image_rect.Width(),
5364 upload_height, depth, format, type, bytes);
5365 }
5366 }
5367 }
5368
texImage2D(GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,ImageData * pixels)5369 void WebGLRenderingContextBase::texImage2D(GLenum target,
5370 GLint level,
5371 GLint internalformat,
5372 GLenum format,
5373 GLenum type,
5374 ImageData* pixels) {
5375 TexImageHelperImageData(kTexImage2D, target, level, internalformat, 0, format,
5376 type, 1, 0, 0, 0, pixels, GetImageDataSize(pixels),
5377 0);
5378 }
5379
TexImageHelperHTMLImageElement(const SecurityOrigin * security_origin,TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,HTMLImageElement * image,const IntRect & source_image_rect,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5380 void WebGLRenderingContextBase::TexImageHelperHTMLImageElement(
5381 const SecurityOrigin* security_origin,
5382 TexImageFunctionID function_id,
5383 GLenum target,
5384 GLint level,
5385 GLint internalformat,
5386 GLenum format,
5387 GLenum type,
5388 GLint xoffset,
5389 GLint yoffset,
5390 GLint zoffset,
5391 HTMLImageElement* image,
5392 const IntRect& source_image_rect,
5393 GLsizei depth,
5394 GLint unpack_image_height,
5395 ExceptionState& exception_state) {
5396 const char* func_name = GetTexImageFunctionName(function_id);
5397 if (isContextLost())
5398 return;
5399
5400 if (!ValidateHTMLImageElement(security_origin, func_name, image,
5401 exception_state))
5402 return;
5403 if (!ValidateTexImageBinding(func_name, function_id, target))
5404 return;
5405
5406 scoped_refptr<Image> image_for_render = image->CachedImage()->GetImage();
5407 bool have_svg_image = IsA<SVGImage>(image_for_render.get());
5408 if (have_svg_image || !image_for_render->HasDefaultOrientation()) {
5409 if (have_svg_image && canvas()) {
5410 UseCounter::Count(canvas()->GetDocument(), WebFeature::kSVGInWebGL);
5411 }
5412 // DrawImageIntoBuffer always respects orientation
5413 image_for_render =
5414 DrawImageIntoBuffer(std::move(image_for_render), image->width(),
5415 image->height(), func_name);
5416 }
5417
5418 TexImageFunctionType function_type;
5419 if (function_id == kTexImage2D || function_id == kTexImage3D)
5420 function_type = kTexImage;
5421 else
5422 function_type = kTexSubImage;
5423 if (!image_for_render ||
5424 !ValidateTexFunc(func_name, function_type, kSourceHTMLImageElement,
5425 target, level, internalformat, image_for_render->width(),
5426 image_for_render->height(), depth, 0, format, type,
5427 xoffset, yoffset, zoffset))
5428 return;
5429
5430 TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
5431 zoffset, format, type, image_for_render.get(),
5432 WebGLImageConversion::kHtmlDomImage, unpack_flip_y_,
5433 unpack_premultiply_alpha_, source_image_rect, depth,
5434 unpack_image_height);
5435 }
5436
texImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,HTMLImageElement * image,ExceptionState & exception_state)5437 void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
5438 GLenum target,
5439 GLint level,
5440 GLint internalformat,
5441 GLenum format,
5442 GLenum type,
5443 HTMLImageElement* image,
5444 ExceptionState& exception_state) {
5445 TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
5446 kTexImage2D, target, level, internalformat,
5447 format, type, 0, 0, 0, image,
5448 SentinelEmptyRect(), 1, 0, exception_state);
5449 }
5450
CanUseTexImageViaGPU(GLenum format,GLenum type)5451 bool WebGLRenderingContextBase::CanUseTexImageViaGPU(GLenum format,
5452 GLenum type) {
5453 #if defined(OS_MAC)
5454 // RGB5_A1 is not color-renderable on NVIDIA Mac, see crbug.com/676209.
5455 // Though, glCopyTextureCHROMIUM can handle RGB5_A1 internalformat by doing a
5456 // fallback path, but it doesn't know the type info. So, we still cannot do
5457 // the fallback path in glCopyTextureCHROMIUM for
5458 // RGBA/RGBA/UNSIGNED_SHORT_5_5_5_1 format and type combination.
5459 if (type == GL_UNSIGNED_SHORT_5_5_5_1)
5460 return false;
5461 #endif
5462
5463 // TODO(kbr): continued bugs are seen on Linux with AMD's drivers handling
5464 // uploads to R8UI textures. crbug.com/710673
5465 if (format == GL_RED_INTEGER)
5466 return false;
5467
5468 #if defined(OS_ANDROID)
5469 // TODO(kbr): bugs were seen on Android devices with NVIDIA GPUs
5470 // when copying hardware-accelerated video textures to
5471 // floating-point textures. Investigate the root cause of this and
5472 // fix it. crbug.com/710874
5473 if (type == GL_FLOAT)
5474 return false;
5475 #endif
5476
5477 // OES_texture_half_float doesn't support HALF_FLOAT_OES type for
5478 // CopyTexImage/CopyTexSubImage. And OES_texture_half_float doesn't require
5479 // HALF_FLOAT_OES type texture to be renderable. So, HALF_FLOAT_OES type
5480 // texture cannot be copied to or drawn to by glCopyTextureCHROMIUM.
5481 if (type == GL_HALF_FLOAT_OES)
5482 return false;
5483
5484 return true;
5485 }
5486
TexImageViaGPU(TexImageFunctionID function_id,WebGLTexture * texture,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,AcceleratedStaticBitmapImage * source_image,WebGLRenderingContextBase * source_canvas_webgl_context,const IntRect & source_sub_rectangle,bool premultiply_alpha,bool flip_y)5487 void WebGLRenderingContextBase::TexImageViaGPU(
5488 TexImageFunctionID function_id,
5489 WebGLTexture* texture,
5490 GLenum target,
5491 GLint level,
5492 GLint xoffset,
5493 GLint yoffset,
5494 GLint zoffset,
5495 AcceleratedStaticBitmapImage* source_image,
5496 WebGLRenderingContextBase* source_canvas_webgl_context,
5497 const IntRect& source_sub_rectangle,
5498 bool premultiply_alpha,
5499 bool flip_y) {
5500 bool have_source_image = source_image;
5501 bool have_source_canvas_webgl_context = source_canvas_webgl_context;
5502 DCHECK(have_source_image ^ have_source_canvas_webgl_context);
5503
5504 int width = source_sub_rectangle.Width();
5505 int height = source_sub_rectangle.Height();
5506
5507 ScopedTexture2DRestorer restorer(this);
5508
5509 GLuint target_texture = texture->Object();
5510 bool possible_direct_copy = false;
5511 if (function_id == kTexImage2D || function_id == kTexSubImage2D) {
5512 possible_direct_copy = Extensions3DUtil::CanUseCopyTextureCHROMIUM(target);
5513 }
5514
5515 GLint copy_x_offset = xoffset;
5516 GLint copy_y_offset = yoffset;
5517 GLenum copy_target = target;
5518
5519 // if direct copy is not possible, create a temporary texture and then copy
5520 // from canvas to temporary texture to target texture.
5521 if (!possible_direct_copy) {
5522 ContextGL()->GenTextures(1, &target_texture);
5523 ContextGL()->BindTexture(GL_TEXTURE_2D, target_texture);
5524 ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
5525 GL_NEAREST);
5526 ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
5527 GL_NEAREST);
5528 ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
5529 GL_CLAMP_TO_EDGE);
5530 ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
5531 GL_CLAMP_TO_EDGE);
5532 ContextGL()->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
5533 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
5534 copy_x_offset = 0;
5535 copy_y_offset = 0;
5536 copy_target = GL_TEXTURE_2D;
5537 }
5538
5539 {
5540 // glCopyTextureCHROMIUM has a DRAW_AND_READBACK path which will call
5541 // texImage2D. So, reset unpack buffer parameters before that.
5542 ScopedUnpackParametersResetRestore temporaryResetUnpack(this);
5543 if (source_image) {
5544 source_image->CopyToTexture(
5545 ContextGL(), target, target_texture, level, premultiply_alpha, flip_y,
5546 IntPoint(xoffset, yoffset), source_sub_rectangle);
5547 } else {
5548 WebGLRenderingContextBase* gl = source_canvas_webgl_context;
5549 if (gl->is_origin_top_left_ && !canvas()->LowLatencyEnabled())
5550 flip_y = !flip_y;
5551 ScopedTexture2DRestorer inner_restorer(gl);
5552 if (!gl->GetDrawingBuffer()->CopyToPlatformTexture(
5553 ContextGL(), target, target_texture, level,
5554 unpack_premultiply_alpha_, !flip_y, IntPoint(xoffset, yoffset),
5555 source_sub_rectangle, kBackBuffer)) {
5556 NOTREACHED();
5557 }
5558 }
5559 }
5560
5561 if (!possible_direct_copy) {
5562 GLuint tmp_fbo;
5563 ContextGL()->GenFramebuffers(1, &tmp_fbo);
5564 ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, tmp_fbo);
5565 ContextGL()->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
5566 GL_TEXTURE_2D, target_texture, 0);
5567 ContextGL()->BindTexture(texture->GetTarget(), texture->Object());
5568 if (function_id == kTexImage2D) {
5569 ContextGL()->CopyTexSubImage2D(target, level, 0, 0, 0, 0, width, height);
5570 } else if (function_id == kTexSubImage2D) {
5571 ContextGL()->CopyTexSubImage2D(target, level, xoffset, yoffset, 0, 0,
5572 width, height);
5573 } else if (function_id == kTexSubImage3D) {
5574 ContextGL()->CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset,
5575 0, 0, width, height);
5576 }
5577 ContextGL()->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
5578 GL_TEXTURE_2D, 0, 0);
5579 RestoreCurrentFramebuffer();
5580 ContextGL()->DeleteFramebuffers(1, &tmp_fbo);
5581 ContextGL()->DeleteTextures(1, &target_texture);
5582 }
5583 }
5584
TexImageHelperCanvasRenderingContextHost(const SecurityOrigin * security_origin,TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,CanvasRenderingContextHost * context_host,const IntRect & source_sub_rectangle,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5585 void WebGLRenderingContextBase::TexImageHelperCanvasRenderingContextHost(
5586 const SecurityOrigin* security_origin,
5587 TexImageFunctionID function_id,
5588 GLenum target,
5589 GLint level,
5590 GLint internalformat,
5591 GLenum format,
5592 GLenum type,
5593 GLint xoffset,
5594 GLint yoffset,
5595 GLint zoffset,
5596 CanvasRenderingContextHost* context_host,
5597 const IntRect& source_sub_rectangle,
5598 GLsizei depth,
5599 GLint unpack_image_height,
5600 ExceptionState& exception_state) {
5601 const char* func_name = GetTexImageFunctionName(function_id);
5602 if (isContextLost())
5603 return;
5604
5605 if (!ValidateCanvasRenderingContextHost(security_origin, func_name,
5606 context_host, exception_state))
5607 return;
5608 WebGLTexture* texture =
5609 ValidateTexImageBinding(func_name, function_id, target);
5610 if (!texture)
5611 return;
5612 TexImageFunctionType function_type;
5613 if (function_id == kTexImage2D)
5614 function_type = kTexImage;
5615 else
5616 function_type = kTexSubImage;
5617 if (!ValidateTexFunc(func_name, function_type, kSourceHTMLCanvasElement,
5618 target, level, internalformat,
5619 source_sub_rectangle.Width(),
5620 source_sub_rectangle.Height(), depth, 0, format, type,
5621 xoffset, yoffset, zoffset))
5622 return;
5623
5624 // Note that the sub-rectangle validation is needed for the GPU-GPU
5625 // copy case, but is redundant for the software upload case
5626 // (texImageImpl).
5627 bool selecting_sub_rectangle = false;
5628 if (!ValidateTexImageSubRectangle(
5629 func_name, function_id, context_host, source_sub_rectangle, depth,
5630 unpack_image_height, &selecting_sub_rectangle)) {
5631 return;
5632 }
5633
5634 bool is_webgl_canvas = context_host->Is3d();
5635 WebGLRenderingContextBase* source_canvas_webgl_context = nullptr;
5636 SourceImageStatus source_image_status = kInvalidSourceImageStatus;
5637 scoped_refptr<Image> image;
5638
5639 bool upload_via_gpu =
5640 (function_id == kTexImage2D || function_id == kTexSubImage2D) &&
5641 CanUseTexImageViaGPU(format, type);
5642
5643 // The Image-based upload path may still be used for WebGL-rendered
5644 // canvases in the case of driver bug workarounds
5645 // (e.g. CanUseTexImageViaGPU returning false).
5646 if (is_webgl_canvas && upload_via_gpu) {
5647 source_canvas_webgl_context =
5648 To<WebGLRenderingContextBase>(context_host->RenderingContext());
5649 } else {
5650 image = context_host->GetSourceImageForCanvas(
5651 &source_image_status,
5652 FloatSize(source_sub_rectangle.Width(), source_sub_rectangle.Height()));
5653 if (source_image_status != kNormalSourceImageStatus)
5654 return;
5655 }
5656
5657 // Still not clear whether we will take the accelerated upload path
5658 // at this point; it depends on what came back from
5659 // CanUseTexImageViaGPU, for example.
5660 auto* static_bitmap_image = DynamicTo<StaticBitmapImage>(image.get());
5661 upload_via_gpu &= source_canvas_webgl_context ||
5662 (static_bitmap_image && image->IsTextureBacked());
5663
5664 if (upload_via_gpu) {
5665 AcceleratedStaticBitmapImage* accel_image = nullptr;
5666 if (image) {
5667 accel_image =
5668 static_cast<AcceleratedStaticBitmapImage*>(static_bitmap_image);
5669 }
5670
5671 // The GPU-GPU copy path uses the Y-up coordinate system.
5672 IntRect adjusted_source_sub_rectangle = source_sub_rectangle;
5673
5674 bool should_adjust_source_sub_rectangle = !unpack_flip_y_;
5675 if (is_origin_top_left_ && source_canvas_webgl_context)
5676 should_adjust_source_sub_rectangle = !should_adjust_source_sub_rectangle;
5677
5678 if (should_adjust_source_sub_rectangle) {
5679 adjusted_source_sub_rectangle.SetY(context_host->Size().Height() -
5680 adjusted_source_sub_rectangle.MaxY());
5681 }
5682
5683 if (function_id == kTexImage2D) {
5684 TexImage2DBase(target, level, internalformat,
5685 source_sub_rectangle.Width(),
5686 source_sub_rectangle.Height(), 0, format, type, nullptr);
5687 TexImageViaGPU(function_id, texture, target, level, 0, 0, 0, accel_image,
5688 source_canvas_webgl_context, adjusted_source_sub_rectangle,
5689 unpack_premultiply_alpha_, unpack_flip_y_);
5690 } else {
5691 TexImageViaGPU(function_id, texture, target, level, xoffset, yoffset, 0,
5692 accel_image, source_canvas_webgl_context,
5693 adjusted_source_sub_rectangle, unpack_premultiply_alpha_,
5694 unpack_flip_y_);
5695 }
5696 } else {
5697 // If these are the 2D functions, the caller must have passed in 1
5698 // for the depth and 0 for the unpack_image_height.
5699 DCHECK(!(function_id == kTexSubImage2D || function_id == kTexSubImage2D) ||
5700 (depth == 1 && unpack_image_height == 0));
5701 // We expect an Image at this point, not a WebGL-rendered canvas.
5702 DCHECK(image);
5703 // TODO(crbug.com/612542): Implement GPU-to-GPU copy path for more
5704 // cases, like copying to layers of 3D textures, and elements of
5705 // 2D texture arrays.
5706 bool flip_y = unpack_flip_y_;
5707 if (is_origin_top_left_ && is_webgl_canvas)
5708 flip_y = !flip_y;
5709
5710 TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
5711 zoffset, format, type, image.get(),
5712 WebGLImageConversion::kHtmlDomCanvas, flip_y,
5713 unpack_premultiply_alpha_, source_sub_rectangle, depth,
5714 unpack_image_height);
5715 }
5716 }
5717
texImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,CanvasRenderingContextHost * context_host,ExceptionState & exception_state)5718 void WebGLRenderingContextBase::texImage2D(
5719 ExecutionContext* execution_context,
5720 GLenum target,
5721 GLint level,
5722 GLint internalformat,
5723 GLenum format,
5724 GLenum type,
5725 CanvasRenderingContextHost* context_host,
5726 ExceptionState& exception_state) {
5727 TexImageHelperCanvasRenderingContextHost(
5728 execution_context->GetSecurityOrigin(), kTexImage2D, target, level,
5729 internalformat, format, type, 0, 0, 0, context_host,
5730 GetTextureSourceSize(context_host), 1, 0, exception_state);
5731 }
5732
VideoFrameToImage(HTMLVideoElement * video,int already_uploaded_id,WebMediaPlayer::VideoFrameUploadMetadata * out_metadata)5733 scoped_refptr<Image> WebGLRenderingContextBase::VideoFrameToImage(
5734 HTMLVideoElement* video,
5735 int already_uploaded_id,
5736 WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
5737 const IntSize& visible_size = video->videoVisibleSize();
5738 if (visible_size.IsEmpty()) {
5739 SynthesizeGLError(GL_INVALID_VALUE, "tex(Sub)Image2D",
5740 "video visible size is empty");
5741 return nullptr;
5742 }
5743 CanvasResourceProvider* resource_provider =
5744 generated_image_cache_.GetCanvasResourceProvider(visible_size);
5745 if (!resource_provider) {
5746 SynthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory");
5747 return nullptr;
5748 }
5749 IntRect dest_rect(0, 0, visible_size.Width(), visible_size.Height());
5750 video->PaintCurrentFrame(resource_provider->Canvas(), dest_rect, nullptr,
5751 already_uploaded_id, out_metadata);
5752 return resource_provider->Snapshot();
5753 }
5754
TexImageHelperHTMLVideoElement(const SecurityOrigin * security_origin,TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,HTMLVideoElement * video,const IntRect & source_image_rect,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5755 void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
5756 const SecurityOrigin* security_origin,
5757 TexImageFunctionID function_id,
5758 GLenum target,
5759 GLint level,
5760 GLint internalformat,
5761 GLenum format,
5762 GLenum type,
5763 GLint xoffset,
5764 GLint yoffset,
5765 GLint zoffset,
5766 HTMLVideoElement* video,
5767 const IntRect& source_image_rect,
5768 GLsizei depth,
5769 GLint unpack_image_height,
5770 ExceptionState& exception_state) {
5771 const char* func_name = GetTexImageFunctionName(function_id);
5772 if (isContextLost())
5773 return;
5774
5775 if (!ValidateHTMLVideoElement(security_origin, func_name, video,
5776 exception_state))
5777 return;
5778 WebGLTexture* texture =
5779 ValidateTexImageBinding(func_name, function_id, target);
5780 if (!texture)
5781 return;
5782 TexImageFunctionType function_type;
5783 if (function_id == kTexImage2D || function_id == kTexImage3D)
5784 function_type = kTexImage;
5785 else
5786 function_type = kTexSubImage;
5787 if (!ValidateTexFunc(func_name, function_type, kSourceHTMLVideoElement,
5788 target, level, internalformat, video->videoWidth(),
5789 video->videoHeight(), 1, 0, format, type, xoffset,
5790 yoffset, zoffset))
5791 return;
5792
5793 GLint adjusted_internalformat =
5794 ConvertTexInternalFormat(internalformat, type);
5795
5796 // For WebGL last-uploaded-frame-metadata API. https://crbug.com/639174
5797 WebMediaPlayer::VideoFrameUploadMetadata frame_metadata = {};
5798 int already_uploaded_id = -1;
5799 WebMediaPlayer::VideoFrameUploadMetadata* frame_metadata_ptr = nullptr;
5800 if (RuntimeEnabledFeatures::ExtraWebGLVideoTextureMetadataEnabled()) {
5801 already_uploaded_id = texture->GetLastUploadedVideoFrameId();
5802 frame_metadata_ptr = &frame_metadata;
5803 }
5804
5805 if (!source_image_rect.IsValid()) {
5806 SynthesizeGLError(GL_INVALID_OPERATION, func_name,
5807 "source sub-rectangle specified via pixel unpack "
5808 "parameters is invalid");
5809 return;
5810 }
5811 bool source_image_rect_is_default =
5812 source_image_rect == SentinelEmptyRect() ||
5813 source_image_rect ==
5814 IntRect(0, 0, video->videoWidth(), video->videoHeight());
5815
5816 const auto& caps = GetDrawingBuffer()->ContextProvider()->GetCapabilities();
5817 const bool may_need_image_external_essl3 =
5818 caps.egl_image_external &&
5819 Extensions3DUtil::CopyTextureCHROMIUMNeedsESSL3(internalformat);
5820 const bool have_image_external_essl3 = caps.egl_image_external_essl3;
5821 const bool use_copyTextureCHROMIUM =
5822 function_id == kTexImage2D && source_image_rect_is_default &&
5823 depth == 1 && GL_TEXTURE_2D == target &&
5824 (have_image_external_essl3 || !may_need_image_external_essl3) &&
5825 CanUseTexImageViaGPU(format, type);
5826
5827 // Format of source video may be 16-bit format, e.g. Y16 format.
5828 // glCopyTextureCHROMIUM requires the source texture to be in 8-bit format.
5829 // Converting 16-bits formated source texture to 8-bits formated texture will
5830 // cause precision lost. So, uploading such video texture to half float or
5831 // float texture can not use GPU-GPU path.
5832 if (use_copyTextureCHROMIUM) {
5833 DCHECK(Extensions3DUtil::CanUseCopyTextureCHROMIUM(target));
5834 DCHECK_EQ(xoffset, 0);
5835 DCHECK_EQ(yoffset, 0);
5836 DCHECK_EQ(zoffset, 0);
5837 // Go through the fast path doing a GPU-GPU textures copy without a readback
5838 // to system memory if possible. Otherwise, it will fall back to the normal
5839 // SW path.
5840
5841 if (video->CopyVideoTextureToPlatformTexture(
5842 ContextGL(), target, texture->Object(), adjusted_internalformat,
5843 format, type, level, unpack_premultiply_alpha_, unpack_flip_y_,
5844 already_uploaded_id, frame_metadata_ptr)) {
5845 texture->UpdateLastUploadedFrame(frame_metadata);
5846 return;
5847 }
5848
5849 // For certain video frame formats (e.g. I420/YUV), if they start on the CPU
5850 // (e.g. video camera frames): upload them to the GPU, do a GPU decode, and
5851 // then copy into the target texture.
5852 if (video->CopyVideoYUVDataToPlatformTexture(
5853 ContextGL(), target, texture->Object(), adjusted_internalformat,
5854 format, type, level, unpack_premultiply_alpha_, unpack_flip_y_,
5855 already_uploaded_id, frame_metadata_ptr)) {
5856 texture->UpdateLastUploadedFrame(frame_metadata);
5857 return;
5858 }
5859 }
5860
5861 if (source_image_rect_is_default) {
5862 // Try using optimized CPU-GPU path for some formats: e.g. Y16 and Y8. It
5863 // leaves early for other formats or if frame is stored on GPU.
5864 ScopedUnpackParametersResetRestore unpack_params(
5865 this, unpack_flip_y_ || unpack_premultiply_alpha_);
5866 if (video->TexImageImpl(
5867 static_cast<WebMediaPlayer::TexImageFunctionID>(function_id),
5868 target, ContextGL(), texture->Object(), level,
5869 adjusted_internalformat, format, type, xoffset, yoffset, zoffset,
5870 unpack_flip_y_,
5871 unpack_premultiply_alpha_ &&
5872 unpack_colorspace_conversion_ == GL_NONE)) {
5873 texture->ClearLastUploadedFrame();
5874 return;
5875 }
5876 }
5877
5878 scoped_refptr<Image> image =
5879 VideoFrameToImage(video, already_uploaded_id, frame_metadata_ptr);
5880 if (!image)
5881 return;
5882 TexImageImpl(function_id, target, level, adjusted_internalformat, xoffset,
5883 yoffset, zoffset, format, type, image.get(),
5884 WebGLImageConversion::kHtmlDomVideo, unpack_flip_y_,
5885 unpack_premultiply_alpha_, source_image_rect, depth,
5886 unpack_image_height);
5887 texture->UpdateLastUploadedFrame(frame_metadata);
5888 }
5889
texImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,HTMLVideoElement * video,ExceptionState & exception_state)5890 void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
5891 GLenum target,
5892 GLint level,
5893 GLint internalformat,
5894 GLenum format,
5895 GLenum type,
5896 HTMLVideoElement* video,
5897 ExceptionState& exception_state) {
5898 TexImageHelperHTMLVideoElement(execution_context->GetSecurityOrigin(),
5899 kTexImage2D, target, level, internalformat,
5900 format, type, 0, 0, 0, video,
5901 SentinelEmptyRect(), 1, 0, exception_state);
5902 }
5903
TexImageHelperImageBitmap(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,ImageBitmap * bitmap,const IntRect & source_sub_rect,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5904 void WebGLRenderingContextBase::TexImageHelperImageBitmap(
5905 TexImageFunctionID function_id,
5906 GLenum target,
5907 GLint level,
5908 GLint internalformat,
5909 GLenum format,
5910 GLenum type,
5911 GLint xoffset,
5912 GLint yoffset,
5913 GLint zoffset,
5914 ImageBitmap* bitmap,
5915 const IntRect& source_sub_rect,
5916 GLsizei depth,
5917 GLint unpack_image_height,
5918 ExceptionState& exception_state) {
5919 const char* func_name = GetTexImageFunctionName(function_id);
5920 if (isContextLost())
5921 return;
5922 if (!ValidateImageBitmap(func_name, bitmap, exception_state))
5923 return;
5924 WebGLTexture* texture =
5925 ValidateTexImageBinding(func_name, function_id, target);
5926 if (!texture)
5927 return;
5928
5929 bool selecting_sub_rectangle = false;
5930 if (!ValidateTexImageSubRectangle(func_name, function_id, bitmap,
5931 source_sub_rect, depth, unpack_image_height,
5932 &selecting_sub_rectangle)) {
5933 return;
5934 }
5935
5936 TexImageFunctionType function_type;
5937 if (function_id == kTexImage2D)
5938 function_type = kTexImage;
5939 else
5940 function_type = kTexSubImage;
5941
5942 GLsizei width = source_sub_rect.Width();
5943 GLsizei height = source_sub_rect.Height();
5944 if (!ValidateTexFunc(func_name, function_type, kSourceImageBitmap, target,
5945 level, internalformat, width, height, depth, 0, format,
5946 type, xoffset, yoffset, zoffset))
5947 return;
5948
5949 scoped_refptr<StaticBitmapImage> image = bitmap->BitmapImage();
5950 DCHECK(image);
5951
5952 // TODO(kbr): make this work for sub-rectangles of ImageBitmaps.
5953 if (function_id != kTexSubImage3D && function_id != kTexImage3D &&
5954 image->IsTextureBacked() && CanUseTexImageViaGPU(format, type) &&
5955 !selecting_sub_rectangle) {
5956 AcceleratedStaticBitmapImage* accel_image =
5957 static_cast<AcceleratedStaticBitmapImage*>(image.get());
5958 // We hard-code premultiply_alpha and flip_y values because these should
5959 // have already been manipulated during construction of the ImageBitmap.
5960 bool premultiply_alpha = true; // TODO(kbr): this looks wrong!
5961 bool flip_y = false;
5962 if (function_id == kTexImage2D) {
5963 TexImage2DBase(target, level, internalformat, width, height, 0, format,
5964 type, nullptr);
5965 TexImageViaGPU(function_id, texture, target, level, 0, 0, 0, accel_image,
5966 nullptr, source_sub_rect, premultiply_alpha, flip_y);
5967 } else if (function_id == kTexSubImage2D) {
5968 TexImageViaGPU(function_id, texture, target, level, xoffset, yoffset, 0,
5969 accel_image, nullptr, source_sub_rect, premultiply_alpha,
5970 flip_y);
5971 }
5972 return;
5973 }
5974
5975 // Apply orientation if necessary
5976 PaintImage paint_image = bitmap->BitmapImage()->PaintImageForCurrentFrame();
5977 if (!image->HasDefaultOrientation()) {
5978 paint_image = Image::ResizeAndOrientImage(
5979 paint_image, image->CurrentFrameOrientation(), FloatSize(1, 1), 1,
5980 kInterpolationNone);
5981 }
5982
5983 // TODO(kbr): refactor this away to use TexImageImpl on image.
5984 sk_sp<SkImage> sk_image = paint_image.GetSwSkImage();
5985 if (!sk_image) {
5986 SynthesizeGLError(GL_OUT_OF_MEMORY, func_name,
5987 "ImageBitmap unexpectedly empty");
5988 return;
5989 }
5990
5991 SkPixmap pixmap;
5992 uint8_t* pixel_data_ptr = nullptr;
5993 Vector<uint8_t> pixel_data;
5994 // PaintImage::GetSwSkImage() can return a lazily generated image which will
5995 // cause peekPixels() to fail. In that case we use CopyBitmapData to force
5996 // image generation.
5997 bool peek_succeed = sk_image->peekPixels(&pixmap);
5998 if (peek_succeed) {
5999 pixel_data_ptr = static_cast<uint8_t*>(pixmap.writable_addr());
6000 } else {
6001 pixel_data = bitmap->CopyBitmapData(
6002 bitmap->IsPremultiplied() ? kPremultiplyAlpha : kUnpremultiplyAlpha);
6003 pixel_data_ptr = pixel_data.data();
6004 }
6005 Vector<uint8_t> data;
6006 bool need_conversion = true;
6007 bool have_peekable_rgba =
6008 (peek_succeed &&
6009 pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType);
6010 bool is_pixel_data_rgba = (have_peekable_rgba || !peek_succeed);
6011 if (is_pixel_data_rgba && format == GL_RGBA && type == GL_UNSIGNED_BYTE &&
6012 !selecting_sub_rectangle && depth == 1) {
6013 need_conversion = false;
6014 } else {
6015 if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
6016 // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
6017 type = GL_FLOAT;
6018 }
6019 WebGLImageConversion::DataFormat data_format;
6020 if (is_pixel_data_rgba) {
6021 data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA8;
6022 } else {
6023 switch (pixmap.colorType()) {
6024 case SkColorType::kBGRA_8888_SkColorType:
6025 data_format = WebGLImageConversion::DataFormat::kDataFormatBGRA8;
6026 break;
6027 case SkColorType::kRGBA_F16_SkColorType:
6028 // Used in ImageBitmap's ApplyColorSpaceConversion.
6029 data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA16F;
6030 break;
6031 default:
6032 // Can not handle this ImageBitmap's format.
6033 SynthesizeGLError(GL_INVALID_VALUE, func_name,
6034 "unsupported color type / space in ImageBitmap");
6035 return;
6036 }
6037 }
6038 // In the case of ImageBitmap, we do not need to apply flipY or
6039 // premultiplyAlpha.
6040 if (!WebGLImageConversion::ExtractImageData(
6041 pixel_data_ptr, data_format, bitmap->Size(), source_sub_rect, depth,
6042 unpack_image_height, format, type, false, false, data)) {
6043 SynthesizeGLError(GL_INVALID_VALUE, func_name,
6044 "error extracting data from ImageBitmap");
6045 return;
6046 }
6047 }
6048 ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
6049 if (function_id == kTexImage2D) {
6050 TexImage2DBase(target, level, internalformat, width, height, 0, format,
6051 type, need_conversion ? data.data() : pixel_data_ptr);
6052 } else if (function_id == kTexSubImage2D) {
6053 ContextGL()->TexSubImage2D(target, level, xoffset, yoffset, width, height,
6054 format, type,
6055 need_conversion ? data.data() : pixel_data_ptr);
6056 } else if (function_id == kTexImage3D) {
6057 ContextGL()->TexImage3D(target, level, internalformat, width, height, depth,
6058 0, format, type,
6059 need_conversion ? data.data() : pixel_data_ptr);
6060 } else {
6061 DCHECK_EQ(function_id, kTexSubImage3D);
6062 ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
6063 height, depth, format, type,
6064 need_conversion ? data.data() : pixel_data_ptr);
6065 }
6066 }
6067
texImage2D(GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,ImageBitmap * bitmap,ExceptionState & exception_state)6068 void WebGLRenderingContextBase::texImage2D(GLenum target,
6069 GLint level,
6070 GLint internalformat,
6071 GLenum format,
6072 GLenum type,
6073 ImageBitmap* bitmap,
6074 ExceptionState& exception_state) {
6075 TexImageHelperImageBitmap(kTexImage2D, target, level, internalformat, format,
6076 type, 0, 0, 0, bitmap, GetTextureSourceSize(bitmap),
6077 1, 0, exception_state);
6078 }
6079
TexParameter(GLenum target,GLenum pname,GLfloat paramf,GLint parami,bool is_float)6080 void WebGLRenderingContextBase::TexParameter(GLenum target,
6081 GLenum pname,
6082 GLfloat paramf,
6083 GLint parami,
6084 bool is_float) {
6085 if (isContextLost())
6086 return;
6087 if (!ValidateTextureBinding("texParameter", target))
6088 return;
6089 switch (pname) {
6090 case GL_TEXTURE_MIN_FILTER:
6091 if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
6092 if ((is_float && paramf != GL_NEAREST && paramf != GL_LINEAR) ||
6093 (!is_float && parami != GL_NEAREST && parami != GL_LINEAR)) {
6094 SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6095 "invalid parameter name");
6096 return;
6097 }
6098 }
6099 break;
6100 case GL_TEXTURE_MAG_FILTER:
6101 break;
6102 case GL_TEXTURE_WRAP_R:
6103 if (!IsWebGL2()) {
6104 SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6105 "invalid parameter name");
6106 return;
6107 }
6108 FALLTHROUGH;
6109 case GL_TEXTURE_WRAP_S:
6110 case GL_TEXTURE_WRAP_T:
6111 if ((is_float && paramf != GL_CLAMP_TO_EDGE &&
6112 paramf != GL_MIRRORED_REPEAT && paramf != GL_REPEAT) ||
6113 (!is_float && parami != GL_CLAMP_TO_EDGE &&
6114 parami != GL_MIRRORED_REPEAT && parami != GL_REPEAT)) {
6115 SynthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter");
6116 return;
6117 }
6118
6119 if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
6120 if ((is_float && paramf != GL_CLAMP_TO_EDGE) ||
6121 (!is_float && parami != GL_CLAMP_TO_EDGE)) {
6122 SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6123 "invalid parameter");
6124 return;
6125 }
6126 }
6127 break;
6128 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
6129 if (!ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
6130 SynthesizeGLError(
6131 GL_INVALID_ENUM, "texParameter",
6132 "invalid parameter, EXT_texture_filter_anisotropic not enabled");
6133 return;
6134 }
6135 break;
6136 case GL_TEXTURE_COMPARE_FUNC:
6137 case GL_TEXTURE_COMPARE_MODE:
6138 case GL_TEXTURE_BASE_LEVEL:
6139 case GL_TEXTURE_MAX_LEVEL:
6140 case GL_TEXTURE_MAX_LOD:
6141 case GL_TEXTURE_MIN_LOD:
6142 if (!IsWebGL2()) {
6143 SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6144 "invalid parameter name");
6145 return;
6146 }
6147 break;
6148 default:
6149 SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6150 "invalid parameter name");
6151 return;
6152 }
6153 if (is_float) {
6154 ContextGL()->TexParameterf(target, pname, paramf);
6155 } else {
6156 ContextGL()->TexParameteri(target, pname, parami);
6157 }
6158 }
6159
texParameterf(GLenum target,GLenum pname,GLfloat param)6160 void WebGLRenderingContextBase::texParameterf(GLenum target,
6161 GLenum pname,
6162 GLfloat param) {
6163 TexParameter(target, pname, param, 0, true);
6164 }
6165
texParameteri(GLenum target,GLenum pname,GLint param)6166 void WebGLRenderingContextBase::texParameteri(GLenum target,
6167 GLenum pname,
6168 GLint param) {
6169 TexParameter(target, pname, 0, param, false);
6170 }
6171
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,MaybeShared<DOMArrayBufferView> pixels)6172 void WebGLRenderingContextBase::texSubImage2D(
6173 GLenum target,
6174 GLint level,
6175 GLint xoffset,
6176 GLint yoffset,
6177 GLsizei width,
6178 GLsizei height,
6179 GLenum format,
6180 GLenum type,
6181 MaybeShared<DOMArrayBufferView> pixels) {
6182 TexImageHelperDOMArrayBufferView(kTexSubImage2D, target, level, 0, width,
6183 height, 1, 0, format, type, xoffset, yoffset,
6184 0, pixels.View(), kNullNotAllowed, 0);
6185 }
6186
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,ImageData * pixels)6187 void WebGLRenderingContextBase::texSubImage2D(GLenum target,
6188 GLint level,
6189 GLint xoffset,
6190 GLint yoffset,
6191 GLenum format,
6192 GLenum type,
6193 ImageData* pixels) {
6194 TexImageHelperImageData(kTexSubImage2D, target, level, 0, 0, format, type, 1,
6195 xoffset, yoffset, 0, pixels, GetImageDataSize(pixels),
6196 0);
6197 }
6198
texSubImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLImageElement * image,ExceptionState & exception_state)6199 void WebGLRenderingContextBase::texSubImage2D(
6200 ExecutionContext* execution_context,
6201 GLenum target,
6202 GLint level,
6203 GLint xoffset,
6204 GLint yoffset,
6205 GLenum format,
6206 GLenum type,
6207 HTMLImageElement* image,
6208 ExceptionState& exception_state) {
6209 TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
6210 kTexSubImage2D, target, level, 0, format, type,
6211 xoffset, yoffset, 0, image,
6212 SentinelEmptyRect(), 1, 0, exception_state);
6213 }
6214
texSubImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,CanvasRenderingContextHost * context_host,ExceptionState & exception_state)6215 void WebGLRenderingContextBase::texSubImage2D(
6216 ExecutionContext* execution_context,
6217 GLenum target,
6218 GLint level,
6219 GLint xoffset,
6220 GLint yoffset,
6221 GLenum format,
6222 GLenum type,
6223 CanvasRenderingContextHost* context_host,
6224 ExceptionState& exception_state) {
6225 TexImageHelperCanvasRenderingContextHost(
6226 execution_context->GetSecurityOrigin(), kTexSubImage2D, target, level, 0,
6227 format, type, xoffset, yoffset, 0, context_host,
6228 GetTextureSourceSize(context_host), 1, 0, exception_state);
6229 }
6230
texSubImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLVideoElement * video,ExceptionState & exception_state)6231 void WebGLRenderingContextBase::texSubImage2D(
6232 ExecutionContext* execution_context,
6233 GLenum target,
6234 GLint level,
6235 GLint xoffset,
6236 GLint yoffset,
6237 GLenum format,
6238 GLenum type,
6239 HTMLVideoElement* video,
6240 ExceptionState& exception_state) {
6241 TexImageHelperHTMLVideoElement(execution_context->GetSecurityOrigin(),
6242 kTexSubImage2D, target, level, 0, format, type,
6243 xoffset, yoffset, 0, video,
6244 SentinelEmptyRect(), 1, 0, exception_state);
6245 }
6246
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,ImageBitmap * bitmap,ExceptionState & exception_state)6247 void WebGLRenderingContextBase::texSubImage2D(GLenum target,
6248 GLint level,
6249 GLint xoffset,
6250 GLint yoffset,
6251 GLenum format,
6252 GLenum type,
6253 ImageBitmap* bitmap,
6254 ExceptionState& exception_state) {
6255 TexImageHelperImageBitmap(
6256 kTexSubImage2D, target, level, 0, format, type, xoffset, yoffset, 0,
6257 bitmap, GetTextureSourceSize(bitmap), 1, 0, exception_state);
6258 }
6259
uniform1f(const WebGLUniformLocation * location,GLfloat x)6260 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location,
6261 GLfloat x) {
6262 if (isContextLost() || !location)
6263 return;
6264
6265 if (location->Program() != current_program_) {
6266 SynthesizeGLError(GL_INVALID_OPERATION, "uniform1f",
6267 "location not for current program");
6268 return;
6269 }
6270
6271 ContextGL()->Uniform1f(location->Location(), x);
6272 }
6273
uniform1fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6274 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location,
6275 const FlexibleFloat32Array& v) {
6276 if (isContextLost() ||
6277 !ValidateUniformParameters("uniform1fv", location, v, 1, 0, v.length()))
6278 return;
6279
6280 ContextGL()->Uniform1fv(location->Location(),
6281 base::checked_cast<GLuint>(v.length()),
6282 v.DataMaybeOnStack());
6283 }
6284
uniform1fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6285 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location,
6286 Vector<GLfloat>& v) {
6287 if (isContextLost() ||
6288 !ValidateUniformParameters("uniform1fv", location, v.data(), v.size(), 1,
6289 0, v.size()))
6290 return;
6291
6292 ContextGL()->Uniform1fv(location->Location(), v.size(), v.data());
6293 }
6294
uniform1i(const WebGLUniformLocation * location,GLint x)6295 void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location,
6296 GLint x) {
6297 if (isContextLost() || !location)
6298 return;
6299
6300 if (location->Program() != current_program_) {
6301 SynthesizeGLError(GL_INVALID_OPERATION, "uniform1i",
6302 "location not for current program");
6303 return;
6304 }
6305
6306 ContextGL()->Uniform1i(location->Location(), x);
6307 }
6308
uniform1iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6309 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location,
6310 const FlexibleInt32Array& v) {
6311 if (isContextLost() ||
6312 !ValidateUniformParameters("uniform1iv", location, v, 1, 0, v.length()))
6313 return;
6314
6315 ContextGL()->Uniform1iv(location->Location(),
6316 base::checked_cast<GLuint>(v.length()),
6317 v.DataMaybeOnStack());
6318 }
6319
uniform1iv(const WebGLUniformLocation * location,Vector<GLint> & v)6320 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location,
6321 Vector<GLint>& v) {
6322 if (isContextLost() ||
6323 !ValidateUniformParameters("uniform1iv", location, v.data(), v.size(), 1,
6324 0, v.size()))
6325 return;
6326
6327 ContextGL()->Uniform1iv(location->Location(), v.size(), v.data());
6328 }
6329
uniform2f(const WebGLUniformLocation * location,GLfloat x,GLfloat y)6330 void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location,
6331 GLfloat x,
6332 GLfloat y) {
6333 if (isContextLost() || !location)
6334 return;
6335
6336 if (location->Program() != current_program_) {
6337 SynthesizeGLError(GL_INVALID_OPERATION, "uniform2f",
6338 "location not for current program");
6339 return;
6340 }
6341
6342 ContextGL()->Uniform2f(location->Location(), x, y);
6343 }
6344
uniform2fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6345 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location,
6346 const FlexibleFloat32Array& v) {
6347 if (isContextLost() ||
6348 !ValidateUniformParameters("uniform2fv", location, v, 2, 0, v.length()))
6349 return;
6350
6351 ContextGL()->Uniform2fv(location->Location(),
6352 base::checked_cast<GLuint>(v.length()) >> 1,
6353 v.DataMaybeOnStack());
6354 }
6355
uniform2fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6356 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location,
6357 Vector<GLfloat>& v) {
6358 if (isContextLost() ||
6359 !ValidateUniformParameters("uniform2fv", location, v.data(), v.size(), 2,
6360 0, v.size()))
6361 return;
6362
6363 ContextGL()->Uniform2fv(location->Location(), v.size() >> 1, v.data());
6364 }
6365
uniform2i(const WebGLUniformLocation * location,GLint x,GLint y)6366 void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location,
6367 GLint x,
6368 GLint y) {
6369 if (isContextLost() || !location)
6370 return;
6371
6372 if (location->Program() != current_program_) {
6373 SynthesizeGLError(GL_INVALID_OPERATION, "uniform2i",
6374 "location not for current program");
6375 return;
6376 }
6377
6378 ContextGL()->Uniform2i(location->Location(), x, y);
6379 }
6380
uniform2iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6381 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location,
6382 const FlexibleInt32Array& v) {
6383 if (isContextLost() ||
6384 !ValidateUniformParameters("uniform2iv", location, v, 2, 0, v.length()))
6385 return;
6386
6387 ContextGL()->Uniform2iv(location->Location(),
6388 base::checked_cast<GLuint>(v.length()) >> 1,
6389 v.DataMaybeOnStack());
6390 }
6391
uniform2iv(const WebGLUniformLocation * location,Vector<GLint> & v)6392 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location,
6393 Vector<GLint>& v) {
6394 if (isContextLost() ||
6395 !ValidateUniformParameters("uniform2iv", location, v.data(), v.size(), 2,
6396 0, v.size()))
6397 return;
6398
6399 ContextGL()->Uniform2iv(location->Location(), v.size() >> 1, v.data());
6400 }
6401
uniform3f(const WebGLUniformLocation * location,GLfloat x,GLfloat y,GLfloat z)6402 void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location,
6403 GLfloat x,
6404 GLfloat y,
6405 GLfloat z) {
6406 if (isContextLost() || !location)
6407 return;
6408
6409 if (location->Program() != current_program_) {
6410 SynthesizeGLError(GL_INVALID_OPERATION, "uniform3f",
6411 "location not for current program");
6412 return;
6413 }
6414
6415 ContextGL()->Uniform3f(location->Location(), x, y, z);
6416 }
6417
uniform3fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6418 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location,
6419 const FlexibleFloat32Array& v) {
6420 if (isContextLost() ||
6421 !ValidateUniformParameters("uniform3fv", location, v, 3, 0, v.length()))
6422 return;
6423
6424 ContextGL()->Uniform3fv(location->Location(),
6425 base::checked_cast<GLuint>(v.length()) / 3,
6426 v.DataMaybeOnStack());
6427 }
6428
uniform3fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6429 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location,
6430 Vector<GLfloat>& v) {
6431 if (isContextLost() ||
6432 !ValidateUniformParameters("uniform3fv", location, v.data(), v.size(), 3,
6433 0, v.size()))
6434 return;
6435
6436 ContextGL()->Uniform3fv(location->Location(), v.size() / 3, v.data());
6437 }
6438
uniform3i(const WebGLUniformLocation * location,GLint x,GLint y,GLint z)6439 void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location,
6440 GLint x,
6441 GLint y,
6442 GLint z) {
6443 if (isContextLost() || !location)
6444 return;
6445
6446 if (location->Program() != current_program_) {
6447 SynthesizeGLError(GL_INVALID_OPERATION, "uniform3i",
6448 "location not for current program");
6449 return;
6450 }
6451
6452 ContextGL()->Uniform3i(location->Location(), x, y, z);
6453 }
6454
uniform3iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6455 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location,
6456 const FlexibleInt32Array& v) {
6457 if (isContextLost() ||
6458 !ValidateUniformParameters("uniform3iv", location, v, 3, 0, v.length()))
6459 return;
6460
6461 ContextGL()->Uniform3iv(location->Location(),
6462 base::checked_cast<GLuint>(v.length()) / 3,
6463 v.DataMaybeOnStack());
6464 }
6465
uniform3iv(const WebGLUniformLocation * location,Vector<GLint> & v)6466 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location,
6467 Vector<GLint>& v) {
6468 if (isContextLost() ||
6469 !ValidateUniformParameters("uniform3iv", location, v.data(), v.size(), 3,
6470 0, v.size()))
6471 return;
6472
6473 ContextGL()->Uniform3iv(location->Location(), v.size() / 3, v.data());
6474 }
6475
uniform4f(const WebGLUniformLocation * location,GLfloat x,GLfloat y,GLfloat z,GLfloat w)6476 void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location,
6477 GLfloat x,
6478 GLfloat y,
6479 GLfloat z,
6480 GLfloat w) {
6481 if (isContextLost() || !location)
6482 return;
6483
6484 if (location->Program() != current_program_) {
6485 SynthesizeGLError(GL_INVALID_OPERATION, "uniform4f",
6486 "location not for current program");
6487 return;
6488 }
6489
6490 ContextGL()->Uniform4f(location->Location(), x, y, z, w);
6491 }
6492
uniform4fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6493 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location,
6494 const FlexibleFloat32Array& v) {
6495 if (isContextLost() ||
6496 !ValidateUniformParameters("uniform4fv", location, v, 4, 0, v.length()))
6497 return;
6498
6499 ContextGL()->Uniform4fv(location->Location(),
6500 base::checked_cast<GLuint>(v.length()) >> 2,
6501 v.DataMaybeOnStack());
6502 }
6503
uniform4fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6504 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location,
6505 Vector<GLfloat>& v) {
6506 if (isContextLost() ||
6507 !ValidateUniformParameters("uniform4fv", location, v.data(), v.size(), 4,
6508 0, v.size()))
6509 return;
6510
6511 ContextGL()->Uniform4fv(location->Location(), v.size() >> 2, v.data());
6512 }
6513
uniform4i(const WebGLUniformLocation * location,GLint x,GLint y,GLint z,GLint w)6514 void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location,
6515 GLint x,
6516 GLint y,
6517 GLint z,
6518 GLint w) {
6519 if (isContextLost() || !location)
6520 return;
6521
6522 if (location->Program() != current_program_) {
6523 SynthesizeGLError(GL_INVALID_OPERATION, "uniform4i",
6524 "location not for current program");
6525 return;
6526 }
6527
6528 ContextGL()->Uniform4i(location->Location(), x, y, z, w);
6529 }
6530
uniform4iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6531 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location,
6532 const FlexibleInt32Array& v) {
6533 if (isContextLost() ||
6534 !ValidateUniformParameters("uniform4iv", location, v, 4, 0, v.length()))
6535 return;
6536
6537 ContextGL()->Uniform4iv(location->Location(),
6538 base::checked_cast<GLuint>(v.length()) >> 2,
6539 v.DataMaybeOnStack());
6540 }
6541
uniform4iv(const WebGLUniformLocation * location,Vector<GLint> & v)6542 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location,
6543 Vector<GLint>& v) {
6544 if (isContextLost() ||
6545 !ValidateUniformParameters("uniform4iv", location, v.data(), v.size(), 4,
6546 0, v.size()))
6547 return;
6548
6549 ContextGL()->Uniform4iv(location->Location(), v.size() >> 2, v.data());
6550 }
6551
uniformMatrix2fv(const WebGLUniformLocation * location,GLboolean transpose,MaybeShared<DOMFloat32Array> v)6552 void WebGLRenderingContextBase::uniformMatrix2fv(
6553 const WebGLUniformLocation* location,
6554 GLboolean transpose,
6555 MaybeShared<DOMFloat32Array> v) {
6556 if (isContextLost() ||
6557 !ValidateUniformMatrixParameters("uniformMatrix2fv", location, transpose,
6558 v.View(), 4, 0, v.View()->length()))
6559 return;
6560 ContextGL()->UniformMatrix2fv(
6561 location->Location(), base::checked_cast<GLuint>(v.View()->length()) >> 2,
6562 transpose, v.View()->DataMaybeShared());
6563 }
6564
uniformMatrix2fv(const WebGLUniformLocation * location,GLboolean transpose,Vector<GLfloat> & v)6565 void WebGLRenderingContextBase::uniformMatrix2fv(
6566 const WebGLUniformLocation* location,
6567 GLboolean transpose,
6568 Vector<GLfloat>& v) {
6569 if (isContextLost() ||
6570 !ValidateUniformMatrixParameters("uniformMatrix2fv", location, transpose,
6571 v.data(), v.size(), 4, 0, v.size()))
6572 return;
6573 ContextGL()->UniformMatrix2fv(location->Location(), v.size() >> 2, transpose,
6574 v.data());
6575 }
6576
uniformMatrix3fv(const WebGLUniformLocation * location,GLboolean transpose,MaybeShared<DOMFloat32Array> v)6577 void WebGLRenderingContextBase::uniformMatrix3fv(
6578 const WebGLUniformLocation* location,
6579 GLboolean transpose,
6580 MaybeShared<DOMFloat32Array> v) {
6581 if (isContextLost() ||
6582 !ValidateUniformMatrixParameters("uniformMatrix3fv", location, transpose,
6583 v.View(), 9, 0, v.View()->length()))
6584 return;
6585 ContextGL()->UniformMatrix3fv(
6586 location->Location(), base::checked_cast<GLuint>(v.View()->length()) / 9,
6587 transpose, v.View()->DataMaybeShared());
6588 }
6589
uniformMatrix3fv(const WebGLUniformLocation * location,GLboolean transpose,Vector<GLfloat> & v)6590 void WebGLRenderingContextBase::uniformMatrix3fv(
6591 const WebGLUniformLocation* location,
6592 GLboolean transpose,
6593 Vector<GLfloat>& v) {
6594 if (isContextLost() ||
6595 !ValidateUniformMatrixParameters("uniformMatrix3fv", location, transpose,
6596 v.data(), v.size(), 9, 0, v.size()))
6597 return;
6598 ContextGL()->UniformMatrix3fv(location->Location(), v.size() / 9, transpose,
6599 v.data());
6600 }
6601
uniformMatrix4fv(const WebGLUniformLocation * location,GLboolean transpose,MaybeShared<DOMFloat32Array> v)6602 void WebGLRenderingContextBase::uniformMatrix4fv(
6603 const WebGLUniformLocation* location,
6604 GLboolean transpose,
6605 MaybeShared<DOMFloat32Array> v) {
6606 if (isContextLost() ||
6607 !ValidateUniformMatrixParameters("uniformMatrix4fv", location, transpose,
6608 v.View(), 16, 0, v.View()->length()))
6609 return;
6610 ContextGL()->UniformMatrix4fv(
6611 location->Location(), base::checked_cast<GLuint>(v.View()->length()) >> 4,
6612 transpose, v.View()->DataMaybeShared());
6613 }
6614
uniformMatrix4fv(const WebGLUniformLocation * location,GLboolean transpose,Vector<GLfloat> & v)6615 void WebGLRenderingContextBase::uniformMatrix4fv(
6616 const WebGLUniformLocation* location,
6617 GLboolean transpose,
6618 Vector<GLfloat>& v) {
6619 if (isContextLost() ||
6620 !ValidateUniformMatrixParameters("uniformMatrix4fv", location, transpose,
6621 v.data(), v.size(), 16, 0, v.size()))
6622 return;
6623 ContextGL()->UniformMatrix4fv(location->Location(), v.size() >> 4, transpose,
6624 v.data());
6625 }
6626
useProgram(WebGLProgram * program)6627 void WebGLRenderingContextBase::useProgram(WebGLProgram* program) {
6628 if (!ValidateNullableWebGLObject("useProgram", program))
6629 return;
6630 if (program && !program->LinkStatus(this)) {
6631 SynthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid");
6632 return;
6633 }
6634
6635 if (current_program_ != program) {
6636 if (current_program_)
6637 current_program_->OnDetached(ContextGL());
6638 current_program_ = program;
6639 ContextGL()->UseProgram(ObjectOrZero(program));
6640 if (program)
6641 program->OnAttached();
6642 }
6643 }
6644
validateProgram(WebGLProgram * program)6645 void WebGLRenderingContextBase::validateProgram(WebGLProgram* program) {
6646 if (!ValidateWebGLProgramOrShader("validateProgram", program))
6647 return;
6648 ContextGL()->ValidateProgram(ObjectOrZero(program));
6649 }
6650
SetVertexAttribType(GLuint index,VertexAttribValueType type)6651 void WebGLRenderingContextBase::SetVertexAttribType(
6652 GLuint index,
6653 VertexAttribValueType type) {
6654 if (index < max_vertex_attribs_)
6655 vertex_attrib_type_[index] = type;
6656 }
6657
vertexAttrib1f(GLuint index,GLfloat v0)6658 void WebGLRenderingContextBase::vertexAttrib1f(GLuint index, GLfloat v0) {
6659 if (isContextLost())
6660 return;
6661 ContextGL()->VertexAttrib1f(index, v0);
6662 SetVertexAttribType(index, kFloat32ArrayType);
6663 }
6664
vertexAttrib1fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6665 void WebGLRenderingContextBase::vertexAttrib1fv(
6666 GLuint index,
6667 MaybeShared<const DOMFloat32Array> v) {
6668 if (isContextLost())
6669 return;
6670 if (!v.View() || v.View()->length() < 1) {
6671 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array");
6672 return;
6673 }
6674 ContextGL()->VertexAttrib1fv(index, v.View()->DataMaybeShared());
6675 SetVertexAttribType(index, kFloat32ArrayType);
6676 }
6677
vertexAttrib1fv(GLuint index,const Vector<GLfloat> & v)6678 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index,
6679 const Vector<GLfloat>& v) {
6680 if (isContextLost())
6681 return;
6682 if (v.size() < 1) {
6683 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array");
6684 return;
6685 }
6686 ContextGL()->VertexAttrib1fv(index, v.data());
6687 SetVertexAttribType(index, kFloat32ArrayType);
6688 }
6689
vertexAttrib2f(GLuint index,GLfloat v0,GLfloat v1)6690 void WebGLRenderingContextBase::vertexAttrib2f(GLuint index,
6691 GLfloat v0,
6692 GLfloat v1) {
6693 if (isContextLost())
6694 return;
6695 ContextGL()->VertexAttrib2f(index, v0, v1);
6696 SetVertexAttribType(index, kFloat32ArrayType);
6697 }
6698
vertexAttrib2fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6699 void WebGLRenderingContextBase::vertexAttrib2fv(
6700 GLuint index,
6701 MaybeShared<const DOMFloat32Array> v) {
6702 if (isContextLost())
6703 return;
6704 if (!v.View() || v.View()->length() < 2) {
6705 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array");
6706 return;
6707 }
6708 ContextGL()->VertexAttrib2fv(index, v.View()->DataMaybeShared());
6709 SetVertexAttribType(index, kFloat32ArrayType);
6710 }
6711
vertexAttrib2fv(GLuint index,const Vector<GLfloat> & v)6712 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index,
6713 const Vector<GLfloat>& v) {
6714 if (isContextLost())
6715 return;
6716 if (v.size() < 2) {
6717 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array");
6718 return;
6719 }
6720 ContextGL()->VertexAttrib2fv(index, v.data());
6721 SetVertexAttribType(index, kFloat32ArrayType);
6722 }
6723
vertexAttrib3f(GLuint index,GLfloat v0,GLfloat v1,GLfloat v2)6724 void WebGLRenderingContextBase::vertexAttrib3f(GLuint index,
6725 GLfloat v0,
6726 GLfloat v1,
6727 GLfloat v2) {
6728 if (isContextLost())
6729 return;
6730 ContextGL()->VertexAttrib3f(index, v0, v1, v2);
6731 SetVertexAttribType(index, kFloat32ArrayType);
6732 }
6733
vertexAttrib3fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6734 void WebGLRenderingContextBase::vertexAttrib3fv(
6735 GLuint index,
6736 MaybeShared<const DOMFloat32Array> v) {
6737 if (isContextLost())
6738 return;
6739 if (!v.View() || v.View()->length() < 3) {
6740 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array");
6741 return;
6742 }
6743 ContextGL()->VertexAttrib3fv(index, v.View()->DataMaybeShared());
6744 SetVertexAttribType(index, kFloat32ArrayType);
6745 }
6746
vertexAttrib3fv(GLuint index,const Vector<GLfloat> & v)6747 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index,
6748 const Vector<GLfloat>& v) {
6749 if (isContextLost())
6750 return;
6751 if (v.size() < 3) {
6752 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array");
6753 return;
6754 }
6755 ContextGL()->VertexAttrib3fv(index, v.data());
6756 SetVertexAttribType(index, kFloat32ArrayType);
6757 }
6758
vertexAttrib4f(GLuint index,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3)6759 void WebGLRenderingContextBase::vertexAttrib4f(GLuint index,
6760 GLfloat v0,
6761 GLfloat v1,
6762 GLfloat v2,
6763 GLfloat v3) {
6764 if (isContextLost())
6765 return;
6766 ContextGL()->VertexAttrib4f(index, v0, v1, v2, v3);
6767 SetVertexAttribType(index, kFloat32ArrayType);
6768 }
6769
vertexAttrib4fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6770 void WebGLRenderingContextBase::vertexAttrib4fv(
6771 GLuint index,
6772 MaybeShared<const DOMFloat32Array> v) {
6773 if (isContextLost())
6774 return;
6775 if (!v.View() || v.View()->length() < 4) {
6776 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array");
6777 return;
6778 }
6779 ContextGL()->VertexAttrib4fv(index, v.View()->DataMaybeShared());
6780 SetVertexAttribType(index, kFloat32ArrayType);
6781 }
6782
vertexAttrib4fv(GLuint index,const Vector<GLfloat> & v)6783 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index,
6784 const Vector<GLfloat>& v) {
6785 if (isContextLost())
6786 return;
6787 if (v.size() < 4) {
6788 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array");
6789 return;
6790 }
6791 ContextGL()->VertexAttrib4fv(index, v.data());
6792 SetVertexAttribType(index, kFloat32ArrayType);
6793 }
6794
vertexAttribPointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,int64_t offset)6795 void WebGLRenderingContextBase::vertexAttribPointer(GLuint index,
6796 GLint size,
6797 GLenum type,
6798 GLboolean normalized,
6799 GLsizei stride,
6800 int64_t offset) {
6801 if (isContextLost())
6802 return;
6803 if (index >= max_vertex_attribs_) {
6804 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer",
6805 "index out of range");
6806 return;
6807 }
6808 if (!ValidateValueFitNonNegInt32("vertexAttribPointer", "offset", offset))
6809 return;
6810 if (!bound_array_buffer_ && offset != 0) {
6811 SynthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer",
6812 "no ARRAY_BUFFER is bound and offset is non-zero");
6813 return;
6814 }
6815
6816 bound_vertex_array_object_->SetArrayBufferForAttrib(
6817 index, bound_array_buffer_.Get());
6818 ContextGL()->VertexAttribPointer(
6819 index, size, type, normalized, stride,
6820 reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
6821 }
6822
VertexAttribDivisorANGLE(GLuint index,GLuint divisor)6823 void WebGLRenderingContextBase::VertexAttribDivisorANGLE(GLuint index,
6824 GLuint divisor) {
6825 if (isContextLost())
6826 return;
6827
6828 if (index >= max_vertex_attribs_) {
6829 SynthesizeGLError(GL_INVALID_VALUE, "vertexAttribDivisorANGLE",
6830 "index out of range");
6831 return;
6832 }
6833
6834 ContextGL()->VertexAttribDivisorANGLE(index, divisor);
6835 }
6836
viewport(GLint x,GLint y,GLsizei width,GLsizei height)6837 void WebGLRenderingContextBase::viewport(GLint x,
6838 GLint y,
6839 GLsizei width,
6840 GLsizei height) {
6841 if (isContextLost())
6842 return;
6843 ContextGL()->Viewport(x, y, width, height);
6844 }
6845
6846 // Added to provide a unified interface with CanvasRenderingContext2D. Prefer
6847 // calling forceLostContext instead.
LoseContext(LostContextMode mode)6848 void WebGLRenderingContextBase::LoseContext(LostContextMode mode) {
6849 ForceLostContext(mode, kManual);
6850 }
6851
ForceLostContext(LostContextMode mode,AutoRecoveryMethod auto_recovery_method)6852 void WebGLRenderingContextBase::ForceLostContext(
6853 LostContextMode mode,
6854 AutoRecoveryMethod auto_recovery_method) {
6855 if (isContextLost()) {
6856 SynthesizeGLError(GL_INVALID_OPERATION, "loseContext",
6857 "context already lost");
6858 return;
6859 }
6860
6861 context_group_->LoseContextGroup(mode, auto_recovery_method);
6862 }
6863
LoseContextImpl(WebGLRenderingContextBase::LostContextMode mode,AutoRecoveryMethod auto_recovery_method)6864 void WebGLRenderingContextBase::LoseContextImpl(
6865 WebGLRenderingContextBase::LostContextMode mode,
6866 AutoRecoveryMethod auto_recovery_method) {
6867 if (isContextLost())
6868 return;
6869
6870 context_lost_mode_ = mode;
6871 DCHECK_NE(context_lost_mode_, kNotLostContext);
6872 auto_recovery_method_ = auto_recovery_method;
6873
6874 // Lose all the extensions.
6875 for (ExtensionTracker* tracker : extensions_) {
6876 tracker->LoseExtension(false);
6877 }
6878
6879 for (wtf_size_t i = 0; i < kWebGLExtensionNameCount; ++i)
6880 extension_enabled_[i] = false;
6881
6882 RemoveAllCompressedTextureFormats();
6883
6884 // If the DrawingBuffer is destroyed during a real lost context event it
6885 // causes the CommandBufferProxy that the DrawingBuffer owns, which is what
6886 // issued the lost context event in the first place, to be destroyed before
6887 // the event is done being handled. This causes a crash when an outstanding
6888 // AutoLock goes out of scope. To avoid this, we create a no-op task to hold
6889 // a reference to the DrawingBuffer until this function is done executing.
6890 if (mode == kRealLostContext) {
6891 task_runner_->PostTask(
6892 FROM_HERE,
6893 WTF::Bind(&WebGLRenderingContextBase::HoldReferenceToDrawingBuffer,
6894 WrapWeakPersistent(this), WTF::RetainedRef(drawing_buffer_)));
6895 }
6896
6897 // Always destroy the context, regardless of context loss mode. This will
6898 // set drawing_buffer_ to null, but it won't actually be destroyed until the
6899 // above task is executed. drawing_buffer_ is recreated in the event that the
6900 // context is restored by MaybeRestoreContext. If this was a real lost context
6901 // the OpenGL calls done during DrawingBuffer destruction will be ignored.
6902 DestroyContext();
6903
6904 ConsoleDisplayPreference display =
6905 (mode == kRealLostContext) ? kDisplayInConsole : kDontDisplayInConsole;
6906 SynthesizeGLError(GC3D_CONTEXT_LOST_WEBGL, "loseContext", "context lost",
6907 display);
6908
6909 // Don't allow restoration unless the context lost event has both been
6910 // dispatched and its default behavior prevented.
6911 restore_allowed_ = false;
6912 DeactivateContext(this);
6913 if (auto_recovery_method_ == kWhenAvailable)
6914 AddToEvictedList(this);
6915
6916 // Always defer the dispatch of the context lost event, to implement
6917 // the spec behavior of queueing a task.
6918 dispatch_context_lost_event_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
6919 }
6920
HoldReferenceToDrawingBuffer(DrawingBuffer *)6921 void WebGLRenderingContextBase::HoldReferenceToDrawingBuffer(DrawingBuffer*) {
6922 // This function intentionally left blank.
6923 }
6924
ForceRestoreContext()6925 void WebGLRenderingContextBase::ForceRestoreContext() {
6926 if (!isContextLost()) {
6927 SynthesizeGLError(GL_INVALID_OPERATION, "restoreContext",
6928 "context not lost");
6929 return;
6930 }
6931
6932 if (!restore_allowed_) {
6933 if (context_lost_mode_ == kWebGLLoseContextLostContext)
6934 SynthesizeGLError(GL_INVALID_OPERATION, "restoreContext",
6935 "context restoration not allowed");
6936 return;
6937 }
6938
6939 if (!restore_timer_.IsActive())
6940 restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
6941 }
6942
NumberOfContextLosses() const6943 uint32_t WebGLRenderingContextBase::NumberOfContextLosses() const {
6944 return context_group_->NumberOfContextLosses();
6945 }
6946
CcLayer() const6947 cc::Layer* WebGLRenderingContextBase::CcLayer() const {
6948 return isContextLost() ? nullptr : GetDrawingBuffer()->CcLayer();
6949 }
6950
SetFilterQuality(SkFilterQuality filter_quality)6951 void WebGLRenderingContextBase::SetFilterQuality(
6952 SkFilterQuality filter_quality) {
6953 if (!isContextLost() && GetDrawingBuffer()) {
6954 GetDrawingBuffer()->SetFilterQuality(filter_quality);
6955 }
6956 }
6957
ExtensionsUtil()6958 Extensions3DUtil* WebGLRenderingContextBase::ExtensionsUtil() {
6959 if (!extensions_util_) {
6960 gpu::gles2::GLES2Interface* gl = ContextGL();
6961 extensions_util_ = Extensions3DUtil::Create(gl);
6962 // The only reason the ExtensionsUtil should be invalid is if the gl context
6963 // is lost.
6964 DCHECK(extensions_util_->IsValid() ||
6965 gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
6966 }
6967 return extensions_util_.get();
6968 }
6969
Stop()6970 void WebGLRenderingContextBase::Stop() {
6971 if (!isContextLost()) {
6972 // Never attempt to restore the context because the page is being torn down.
6973 ForceLostContext(kSyntheticLostContext, kManual);
6974 }
6975 }
6976
DrawingBufferClientIsBoundForDraw()6977 bool WebGLRenderingContextBase::DrawingBufferClientIsBoundForDraw() {
6978 return !framebuffer_binding_;
6979 }
6980
DrawingBufferClientRestoreScissorTest()6981 void WebGLRenderingContextBase::DrawingBufferClientRestoreScissorTest() {
6982 if (destruction_in_progress_)
6983 return;
6984 if (!ContextGL())
6985 return;
6986 if (scissor_enabled_)
6987 ContextGL()->Enable(GL_SCISSOR_TEST);
6988 else
6989 ContextGL()->Disable(GL_SCISSOR_TEST);
6990 }
6991
DrawingBufferClientRestoreMaskAndClearValues()6992 void WebGLRenderingContextBase::DrawingBufferClientRestoreMaskAndClearValues() {
6993 if (destruction_in_progress_)
6994 return;
6995 if (!ContextGL())
6996 return;
6997 bool color_mask_alpha =
6998 color_mask_[3] && active_scoped_rgb_emulation_color_masks_ == 0;
6999 ContextGL()->ColorMask(color_mask_[0], color_mask_[1], color_mask_[2],
7000 color_mask_alpha);
7001 ContextGL()->DepthMask(depth_mask_);
7002 ContextGL()->StencilMaskSeparate(GL_FRONT, stencil_mask_);
7003
7004 ContextGL()->ClearColor(clear_color_[0], clear_color_[1], clear_color_[2],
7005 clear_color_[3]);
7006 ContextGL()->ClearDepthf(clear_depth_);
7007 ContextGL()->ClearStencil(clear_stencil_);
7008 }
7009
7010 void WebGLRenderingContextBase::
DrawingBufferClientRestorePixelPackParameters()7011 DrawingBufferClientRestorePixelPackParameters() {
7012 if (destruction_in_progress_)
7013 return;
7014 if (!ContextGL())
7015 return;
7016 ContextGL()->PixelStorei(GL_PACK_ALIGNMENT, pack_alignment_);
7017 }
7018
DrawingBufferClientRestoreTexture2DBinding()7019 void WebGLRenderingContextBase::DrawingBufferClientRestoreTexture2DBinding() {
7020 if (destruction_in_progress_)
7021 return;
7022 if (!ContextGL())
7023 return;
7024 RestoreCurrentTexture2D();
7025 }
7026
7027 void WebGLRenderingContextBase::
DrawingBufferClientRestoreTextureCubeMapBinding()7028 DrawingBufferClientRestoreTextureCubeMapBinding() {
7029 if (destruction_in_progress_)
7030 return;
7031 if (!ContextGL())
7032 return;
7033 RestoreCurrentTextureCubeMap();
7034 }
7035
7036 void WebGLRenderingContextBase::
DrawingBufferClientRestoreRenderbufferBinding()7037 DrawingBufferClientRestoreRenderbufferBinding() {
7038 if (destruction_in_progress_)
7039 return;
7040 if (!ContextGL())
7041 return;
7042 ContextGL()->BindRenderbuffer(GL_RENDERBUFFER,
7043 ObjectOrZero(renderbuffer_binding_.Get()));
7044 }
7045
DrawingBufferClientRestoreFramebufferBinding()7046 void WebGLRenderingContextBase::DrawingBufferClientRestoreFramebufferBinding() {
7047 if (destruction_in_progress_)
7048 return;
7049 if (!ContextGL())
7050 return;
7051 RestoreCurrentFramebuffer();
7052 }
7053
7054 void WebGLRenderingContextBase::
DrawingBufferClientRestorePixelUnpackBufferBinding()7055 DrawingBufferClientRestorePixelUnpackBufferBinding() {}
7056 void WebGLRenderingContextBase::
DrawingBufferClientRestorePixelPackBufferBinding()7057 DrawingBufferClientRestorePixelPackBufferBinding() {}
7058
7059 bool WebGLRenderingContextBase::
DrawingBufferClientUserAllocatedMultisampledRenderbuffers()7060 DrawingBufferClientUserAllocatedMultisampledRenderbuffers() {
7061 return number_of_user_allocated_multisampled_renderbuffers_ > 0;
7062 }
7063
7064 void WebGLRenderingContextBase::
DrawingBufferClientForceLostContextWithAutoRecovery()7065 DrawingBufferClientForceLostContextWithAutoRecovery() {
7066 ForceLostContext(WebGLRenderingContextBase::kSyntheticLostContext,
7067 WebGLRenderingContextBase::kAuto);
7068 }
7069
GetBooleanParameter(ScriptState * script_state,GLenum pname)7070 ScriptValue WebGLRenderingContextBase::GetBooleanParameter(
7071 ScriptState* script_state,
7072 GLenum pname) {
7073 GLboolean value = 0;
7074 if (!isContextLost())
7075 ContextGL()->GetBooleanv(pname, &value);
7076 return WebGLAny(script_state, static_cast<bool>(value));
7077 }
7078
GetBooleanArrayParameter(ScriptState * script_state,GLenum pname)7079 ScriptValue WebGLRenderingContextBase::GetBooleanArrayParameter(
7080 ScriptState* script_state,
7081 GLenum pname) {
7082 if (pname != GL_COLOR_WRITEMASK) {
7083 NOTIMPLEMENTED();
7084 return WebGLAny(script_state, nullptr, 0);
7085 }
7086 GLboolean value[4] = {0};
7087 if (!isContextLost())
7088 ContextGL()->GetBooleanv(pname, value);
7089 bool bool_value[4];
7090 for (int ii = 0; ii < 4; ++ii)
7091 bool_value[ii] = static_cast<bool>(value[ii]);
7092 return WebGLAny(script_state, bool_value, 4);
7093 }
7094
GetFloatParameter(ScriptState * script_state,GLenum pname)7095 ScriptValue WebGLRenderingContextBase::GetFloatParameter(
7096 ScriptState* script_state,
7097 GLenum pname) {
7098 GLfloat value = 0;
7099 if (!isContextLost())
7100 ContextGL()->GetFloatv(pname, &value);
7101 if (IdentifiabilityStudySettings::Get()->ShouldSample(
7102 blink::IdentifiableSurface::Type::kWebGLParameter)) {
7103 RecordIdentifiableGLParameterDigest(pname, value);
7104 }
7105 return WebGLAny(script_state, value);
7106 }
7107
GetIntParameter(ScriptState * script_state,GLenum pname)7108 ScriptValue WebGLRenderingContextBase::GetIntParameter(
7109 ScriptState* script_state,
7110 GLenum pname) {
7111 GLint value = 0;
7112 if (!isContextLost()) {
7113 ContextGL()->GetIntegerv(pname, &value);
7114 switch (pname) {
7115 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
7116 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
7117 if (value == 0) {
7118 // This indicates read framebuffer is incomplete and an
7119 // INVALID_OPERATION has been generated.
7120 return ScriptValue::CreateNull(script_state->GetIsolate());
7121 }
7122 break;
7123 default:
7124 break;
7125 }
7126 }
7127 if (IdentifiabilityStudySettings::Get()->ShouldSample(
7128 blink::IdentifiableSurface::Type::kWebGLParameter)) {
7129 RecordIdentifiableGLParameterDigest(pname, value);
7130 }
7131 return WebGLAny(script_state, value);
7132 }
7133
GetInt64Parameter(ScriptState * script_state,GLenum pname)7134 ScriptValue WebGLRenderingContextBase::GetInt64Parameter(
7135 ScriptState* script_state,
7136 GLenum pname) {
7137 GLint64 value = 0;
7138 if (!isContextLost())
7139 ContextGL()->GetInteger64v(pname, &value);
7140 return WebGLAny(script_state, value);
7141 }
7142
GetUnsignedIntParameter(ScriptState * script_state,GLenum pname)7143 ScriptValue WebGLRenderingContextBase::GetUnsignedIntParameter(
7144 ScriptState* script_state,
7145 GLenum pname) {
7146 GLint value = 0;
7147 if (!isContextLost())
7148 ContextGL()->GetIntegerv(pname, &value);
7149 return WebGLAny(script_state, static_cast<unsigned>(value));
7150 }
7151
GetWebGLFloatArrayParameter(ScriptState * script_state,GLenum pname)7152 ScriptValue WebGLRenderingContextBase::GetWebGLFloatArrayParameter(
7153 ScriptState* script_state,
7154 GLenum pname) {
7155 GLfloat value[4] = {0};
7156 if (!isContextLost())
7157 ContextGL()->GetFloatv(pname, value);
7158 unsigned length = 0;
7159 switch (pname) {
7160 case GL_ALIASED_POINT_SIZE_RANGE:
7161 case GL_ALIASED_LINE_WIDTH_RANGE:
7162 case GL_DEPTH_RANGE:
7163 length = 2;
7164 break;
7165 case GL_BLEND_COLOR:
7166 case GL_COLOR_CLEAR_VALUE:
7167 length = 4;
7168 break;
7169 default:
7170 NOTIMPLEMENTED();
7171 }
7172 if (ShouldMeasureGLParam(pname)) {
7173 blink::IdentifiableTokenBuilder builder;
7174 for (unsigned i = 0; i < length; i++) {
7175 builder.AddValue(value[i]);
7176 }
7177 RecordIdentifiableGLParameterDigest(pname, builder.GetToken());
7178 }
7179 return WebGLAny(script_state, DOMFloat32Array::Create(value, length));
7180 }
7181
GetWebGLIntArrayParameter(ScriptState * script_state,GLenum pname)7182 ScriptValue WebGLRenderingContextBase::GetWebGLIntArrayParameter(
7183 ScriptState* script_state,
7184 GLenum pname) {
7185 GLint value[4] = {0};
7186 if (!isContextLost())
7187 ContextGL()->GetIntegerv(pname, value);
7188 unsigned length = 0;
7189 switch (pname) {
7190 case GL_MAX_VIEWPORT_DIMS:
7191 length = 2;
7192 break;
7193 case GL_SCISSOR_BOX:
7194 case GL_VIEWPORT:
7195 length = 4;
7196 break;
7197 default:
7198 NOTIMPLEMENTED();
7199 }
7200 if (ShouldMeasureGLParam(pname)) {
7201 blink::IdentifiableTokenBuilder builder;
7202 for (unsigned i = 0; i < length; i++) {
7203 builder.AddValue(value[i]);
7204 }
7205 RecordIdentifiableGLParameterDigest(pname, builder.GetToken());
7206 }
7207 return WebGLAny(script_state, DOMInt32Array::Create(value, length));
7208 }
7209
ValidateTexture2DBinding(const char * function_name,GLenum target)7210 WebGLTexture* WebGLRenderingContextBase::ValidateTexture2DBinding(
7211 const char* function_name,
7212 GLenum target) {
7213 WebGLTexture* tex = nullptr;
7214 switch (target) {
7215 case GL_TEXTURE_2D:
7216 tex = texture_units_[active_texture_unit_].texture2d_binding_.Get();
7217 break;
7218 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
7219 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
7220 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
7221 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
7222 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
7223 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
7224 tex =
7225 texture_units_[active_texture_unit_].texture_cube_map_binding_.Get();
7226 break;
7227 default:
7228 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7229 "invalid texture target");
7230 return nullptr;
7231 }
7232 if (!tex)
7233 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7234 "no texture bound to target");
7235 return tex;
7236 }
7237
ValidateTextureBinding(const char * function_name,GLenum target)7238 WebGLTexture* WebGLRenderingContextBase::ValidateTextureBinding(
7239 const char* function_name,
7240 GLenum target) {
7241 WebGLTexture* tex = nullptr;
7242 switch (target) {
7243 case GL_TEXTURE_2D:
7244 tex = texture_units_[active_texture_unit_].texture2d_binding_.Get();
7245 break;
7246 case GL_TEXTURE_CUBE_MAP:
7247 tex =
7248 texture_units_[active_texture_unit_].texture_cube_map_binding_.Get();
7249 break;
7250 case GL_TEXTURE_3D:
7251 if (!IsWebGL2()) {
7252 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7253 "invalid texture target");
7254 return nullptr;
7255 }
7256 tex = texture_units_[active_texture_unit_].texture3d_binding_.Get();
7257 break;
7258 case GL_TEXTURE_2D_ARRAY:
7259 if (!IsWebGL2()) {
7260 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7261 "invalid texture target");
7262 return nullptr;
7263 }
7264 tex = texture_units_[active_texture_unit_].texture2d_array_binding_.Get();
7265 break;
7266 case GL_TEXTURE_VIDEO_IMAGE_WEBGL:
7267 if (!ExtensionEnabled(kWebGLVideoTextureName)) {
7268 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7269 "invalid texture target");
7270 return nullptr;
7271 }
7272 tex = texture_units_[active_texture_unit_]
7273 .texture_video_image_binding_.Get();
7274 break;
7275 default:
7276 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7277 "invalid texture target");
7278 return nullptr;
7279 }
7280 if (!tex)
7281 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7282 "no texture bound to target");
7283 return tex;
7284 }
7285
ValidateLocationLength(const char * function_name,const String & string)7286 bool WebGLRenderingContextBase::ValidateLocationLength(
7287 const char* function_name,
7288 const String& string) {
7289 const unsigned max_web_gl_location_length = GetMaxWebGLLocationLength();
7290 if (string.length() > max_web_gl_location_length) {
7291 SynthesizeGLError(GL_INVALID_VALUE, function_name, "location length > 256");
7292 return false;
7293 }
7294 return true;
7295 }
7296
ValidateSize(const char * function_name,GLint x,GLint y,GLint z)7297 bool WebGLRenderingContextBase::ValidateSize(const char* function_name,
7298 GLint x,
7299 GLint y,
7300 GLint z) {
7301 if (x < 0 || y < 0 || z < 0) {
7302 SynthesizeGLError(GL_INVALID_VALUE, function_name, "size < 0");
7303 return false;
7304 }
7305 return true;
7306 }
7307
ValidateCharacter(unsigned char c)7308 bool WebGLRenderingContextBase::ValidateCharacter(unsigned char c) {
7309 // Printing characters are valid except " $ ` @ \ ' DEL.
7310 if (c >= 32 && c <= 126 && c != '"' && c != '$' && c != '`' && c != '@' &&
7311 c != '\\' && c != '\'')
7312 return true;
7313 // Horizontal tab, line feed, vertical tab, form feed, carriage return
7314 // are also valid.
7315 if (c >= 9 && c <= 13)
7316 return true;
7317 return false;
7318 }
7319
ValidateString(const char * function_name,const String & string)7320 bool WebGLRenderingContextBase::ValidateString(const char* function_name,
7321 const String& string) {
7322 for (wtf_size_t i = 0; i < string.length(); ++i) {
7323 if (!ValidateCharacter(string[i])) {
7324 SynthesizeGLError(GL_INVALID_VALUE, function_name, "string not ASCII");
7325 return false;
7326 }
7327 }
7328 return true;
7329 }
7330
IsPrefixReserved(const String & name)7331 bool WebGLRenderingContextBase::IsPrefixReserved(const String& name) {
7332 if (name.StartsWith("gl_") || name.StartsWith("webgl_") ||
7333 name.StartsWith("_webgl_"))
7334 return true;
7335 return false;
7336 }
7337
ValidateShaderType(const char * function_name,GLenum shader_type)7338 bool WebGLRenderingContextBase::ValidateShaderType(const char* function_name,
7339 GLenum shader_type) {
7340 switch (shader_type) {
7341 case GL_VERTEX_SHADER:
7342 case GL_FRAGMENT_SHADER:
7343 return true;
7344 default:
7345 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid shader type");
7346 return false;
7347 }
7348 }
7349
AddExtensionSupportedFormatsTypes()7350 void WebGLRenderingContextBase::AddExtensionSupportedFormatsTypes() {
7351 if (!is_oes_texture_float_formats_types_added_ &&
7352 ExtensionEnabled(kOESTextureFloatName)) {
7353 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesOESTexFloat);
7354 ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7355 kSupportedTypesOESTexFloat);
7356 is_oes_texture_float_formats_types_added_ = true;
7357 }
7358
7359 if (!is_oes_texture_half_float_formats_types_added_ &&
7360 ExtensionEnabled(kOESTextureHalfFloatName)) {
7361 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesOESTexHalfFloat);
7362 ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7363 kSupportedTypesOESTexHalfFloat);
7364 is_oes_texture_half_float_formats_types_added_ = true;
7365 }
7366
7367 if (!is_web_gl_depth_texture_formats_types_added_ &&
7368 ExtensionEnabled(kWebGLDepthTextureName)) {
7369 ADD_VALUES_TO_SET(supported_internal_formats_,
7370 kSupportedInternalFormatsOESDepthTex);
7371 ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7372 kSupportedInternalFormatsOESDepthTex);
7373 ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsOESDepthTex);
7374 ADD_VALUES_TO_SET(supported_tex_image_source_formats_,
7375 kSupportedFormatsOESDepthTex);
7376 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesOESDepthTex);
7377 ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7378 kSupportedTypesOESDepthTex);
7379 is_web_gl_depth_texture_formats_types_added_ = true;
7380 }
7381
7382 if (!is_ext_srgb_formats_types_added_ && ExtensionEnabled(kEXTsRGBName)) {
7383 ADD_VALUES_TO_SET(supported_internal_formats_,
7384 kSupportedInternalFormatsEXTsRGB);
7385 ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7386 kSupportedInternalFormatsEXTsRGB);
7387 ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsEXTsRGB);
7388 ADD_VALUES_TO_SET(supported_tex_image_source_formats_,
7389 kSupportedFormatsEXTsRGB);
7390 is_ext_srgb_formats_types_added_ = true;
7391 }
7392 }
7393
AddExtensionSupportedFormatsTypesWebGL2()7394 void WebGLRenderingContextBase::AddExtensionSupportedFormatsTypesWebGL2() {
7395 if (!is_ext_texture_norm16_added_ &&
7396 ExtensionEnabled(kEXTTextureNorm16Name)) {
7397 ADD_VALUES_TO_SET(supported_internal_formats_,
7398 kSupportedInternalFormatsEXTTextureNorm16ES3);
7399 ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7400 kSupportedInternalFormatsEXTTextureNorm16ES3);
7401 ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsEXTTextureNorm16ES3);
7402 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesEXTTextureNorm16ES3);
7403 is_ext_texture_norm16_added_ = true;
7404 }
7405 }
7406
ValidateTexImageSourceFormatAndType(const char * function_name,TexImageFunctionType function_type,GLenum internalformat,GLenum format,GLenum type)7407 bool WebGLRenderingContextBase::ValidateTexImageSourceFormatAndType(
7408 const char* function_name,
7409 TexImageFunctionType function_type,
7410 GLenum internalformat,
7411 GLenum format,
7412 GLenum type) {
7413 if (!is_web_gl2_tex_image_source_formats_types_added_ && IsWebGL2()) {
7414 ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7415 kSupportedInternalFormatsTexImageSourceES3);
7416 ADD_VALUES_TO_SET(supported_tex_image_source_formats_,
7417 kSupportedFormatsTexImageSourceES3);
7418 ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7419 kSupportedTypesTexImageSourceES3);
7420 is_web_gl2_tex_image_source_formats_types_added_ = true;
7421 }
7422
7423 if (!IsWebGL2()) {
7424 AddExtensionSupportedFormatsTypes();
7425 } else {
7426 AddExtensionSupportedFormatsTypesWebGL2();
7427 }
7428
7429 if (internalformat != 0 &&
7430 supported_tex_image_source_internal_formats_.find(internalformat) ==
7431 supported_tex_image_source_internal_formats_.end()) {
7432 if (function_type == kTexImage) {
7433 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7434 "invalid internalformat");
7435 } else {
7436 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7437 "invalid internalformat");
7438 }
7439 return false;
7440 }
7441 if (supported_tex_image_source_formats_.find(format) ==
7442 supported_tex_image_source_formats_.end()) {
7443 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid format");
7444 return false;
7445 }
7446 if (supported_tex_image_source_types_.find(type) ==
7447 supported_tex_image_source_types_.end()) {
7448 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid type");
7449 return false;
7450 }
7451
7452 return true;
7453 }
7454
ValidateTexFuncFormatAndType(const char * function_name,TexImageFunctionType function_type,GLenum internalformat,GLenum format,GLenum type,GLint level)7455 bool WebGLRenderingContextBase::ValidateTexFuncFormatAndType(
7456 const char* function_name,
7457 TexImageFunctionType function_type,
7458 GLenum internalformat,
7459 GLenum format,
7460 GLenum type,
7461 GLint level) {
7462 if (!is_web_gl2_formats_types_added_ && IsWebGL2()) {
7463 ADD_VALUES_TO_SET(supported_internal_formats_,
7464 kSupportedInternalFormatsES3);
7465 ADD_VALUES_TO_SET(supported_internal_formats_,
7466 kSupportedInternalFormatsTexImageES3);
7467 ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsES3);
7468 ADD_VALUES_TO_SET(supported_types_, kSupportedTypesES3);
7469 is_web_gl2_formats_types_added_ = true;
7470 }
7471
7472 if (!IsWebGL2()) {
7473 AddExtensionSupportedFormatsTypes();
7474 } else {
7475 AddExtensionSupportedFormatsTypesWebGL2();
7476 }
7477
7478 if (internalformat != 0 && supported_internal_formats_.find(internalformat) ==
7479 supported_internal_formats_.end()) {
7480 if (function_type == kTexImage) {
7481 if (compressed_texture_formats_.Contains(internalformat)) {
7482 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7483 "compressed texture formats are not accepted");
7484 } else {
7485 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7486 "invalid internalformat");
7487 }
7488 } else {
7489 SynthesizeGLError(GL_INVALID_ENUM, function_name,
7490 "invalid internalformat");
7491 }
7492 return false;
7493 }
7494 if (supported_formats_.find(format) == supported_formats_.end()) {
7495 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid format");
7496 return false;
7497 }
7498 if (supported_types_.find(type) == supported_types_.end()) {
7499 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid type");
7500 return false;
7501 }
7502
7503 if (format == GL_DEPTH_COMPONENT && level > 0 && !IsWebGL2()) {
7504 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7505 "level must be 0 for DEPTH_COMPONENT format");
7506 return false;
7507 }
7508 if (format == GL_DEPTH_STENCIL_OES && level > 0 && !IsWebGL2()) {
7509 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7510 "level must be 0 for DEPTH_STENCIL format");
7511 return false;
7512 }
7513
7514 return true;
7515 }
7516
GetMaxTextureLevelForTarget(GLenum target)7517 GLint WebGLRenderingContextBase::GetMaxTextureLevelForTarget(GLenum target) {
7518 switch (target) {
7519 case GL_TEXTURE_2D:
7520 return max_texture_level_;
7521 case GL_TEXTURE_CUBE_MAP:
7522 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
7523 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
7524 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
7525 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
7526 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
7527 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
7528 return max_cube_map_texture_level_;
7529 case GL_TEXTURE_VIDEO_IMAGE_WEBGL:
7530 return 1;
7531 }
7532 return 0;
7533 }
7534
ValidateTexFuncLevel(const char * function_name,GLenum target,GLint level)7535 bool WebGLRenderingContextBase::ValidateTexFuncLevel(const char* function_name,
7536 GLenum target,
7537 GLint level) {
7538 if (level < 0) {
7539 SynthesizeGLError(GL_INVALID_VALUE, function_name, "level < 0");
7540 return false;
7541 }
7542 GLint max_level = GetMaxTextureLevelForTarget(target);
7543 if (max_level && level >= max_level) {
7544 SynthesizeGLError(GL_INVALID_VALUE, function_name, "level out of range");
7545 return false;
7546 }
7547 // This function only checks if level is legal, so we return true and don't
7548 // generate INVALID_ENUM if target is illegal.
7549 return true;
7550 }
7551
ValidateTexFuncDimensions(const char * function_name,TexImageFunctionType function_type,GLenum target,GLint level,GLsizei width,GLsizei height,GLsizei depth)7552 bool WebGLRenderingContextBase::ValidateTexFuncDimensions(
7553 const char* function_name,
7554 TexImageFunctionType function_type,
7555 GLenum target,
7556 GLint level,
7557 GLsizei width,
7558 GLsizei height,
7559 GLsizei depth) {
7560 if (width < 0 || height < 0 || depth < 0) {
7561 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7562 "width, height or depth < 0");
7563 return false;
7564 }
7565
7566 switch (target) {
7567 case GL_TEXTURE_2D:
7568 case GL_TEXTURE_VIDEO_IMAGE_WEBGL:
7569 if (width > (max_texture_size_ >> level) ||
7570 height > (max_texture_size_ >> level)) {
7571 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7572 "width or height out of range");
7573 return false;
7574 }
7575 break;
7576 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
7577 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
7578 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
7579 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
7580 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
7581 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
7582 if (function_type != kTexSubImage && width != height) {
7583 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7584 "width != height for cube map");
7585 return false;
7586 }
7587 // No need to check height here. For texImage width == height.
7588 // For texSubImage that will be checked when checking yoffset + height is
7589 // in range.
7590 if (width > (max_cube_map_texture_size_ >> level)) {
7591 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7592 "width or height out of range for cube map");
7593 return false;
7594 }
7595 break;
7596 case GL_TEXTURE_3D:
7597 if (IsWebGL2()) {
7598 if (width > (max3d_texture_size_ >> level) ||
7599 height > (max3d_texture_size_ >> level) ||
7600 depth > (max3d_texture_size_ >> level)) {
7601 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7602 "width, height or depth out of range");
7603 return false;
7604 }
7605 break;
7606 }
7607 FALLTHROUGH;
7608 case GL_TEXTURE_2D_ARRAY:
7609 if (IsWebGL2()) {
7610 if (width > (max_texture_size_ >> level) ||
7611 height > (max_texture_size_ >> level) ||
7612 depth > max_array_texture_layers_) {
7613 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7614 "width, height or depth out of range");
7615 return false;
7616 }
7617 break;
7618 }
7619 FALLTHROUGH;
7620 default:
7621 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
7622 return false;
7623 }
7624 return true;
7625 }
7626
ValidateTexFuncParameters(const char * function_name,TexImageFunctionType function_type,TexFuncValidationSourceType source_type,GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type)7627 bool WebGLRenderingContextBase::ValidateTexFuncParameters(
7628 const char* function_name,
7629 TexImageFunctionType function_type,
7630 TexFuncValidationSourceType source_type,
7631 GLenum target,
7632 GLint level,
7633 GLenum internalformat,
7634 GLsizei width,
7635 GLsizei height,
7636 GLsizei depth,
7637 GLint border,
7638 GLenum format,
7639 GLenum type) {
7640 // We absolutely have to validate the format and type combination.
7641 // The texImage2D entry points taking HTMLImage, etc. will produce
7642 // temporary data based on this combination, so it must be legal.
7643 if (source_type == kSourceHTMLImageElement ||
7644 source_type == kSourceHTMLCanvasElement ||
7645 source_type == kSourceHTMLVideoElement ||
7646 source_type == kSourceImageData || source_type == kSourceImageBitmap) {
7647 if (!ValidateTexImageSourceFormatAndType(function_name, function_type,
7648 internalformat, format, type)) {
7649 return false;
7650 }
7651 } else {
7652 if (!ValidateTexFuncFormatAndType(function_name, function_type,
7653 internalformat, format, type, level)) {
7654 return false;
7655 }
7656 }
7657
7658 if (!ValidateTexFuncDimensions(function_name, function_type, target, level,
7659 width, height, depth))
7660 return false;
7661
7662 if (border) {
7663 SynthesizeGLError(GL_INVALID_VALUE, function_name, "border != 0");
7664 return false;
7665 }
7666
7667 return true;
7668 }
7669
ValidateTexFuncData(const char * function_name,TexImageDimension tex_dimension,GLint level,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,DOMArrayBufferView * pixels,NullDisposition disposition,GLuint src_offset)7670 bool WebGLRenderingContextBase::ValidateTexFuncData(
7671 const char* function_name,
7672 TexImageDimension tex_dimension,
7673 GLint level,
7674 GLsizei width,
7675 GLsizei height,
7676 GLsizei depth,
7677 GLenum format,
7678 GLenum type,
7679 DOMArrayBufferView* pixels,
7680 NullDisposition disposition,
7681 GLuint src_offset) {
7682 // All calling functions check isContextLost, so a duplicate check is not
7683 // needed here.
7684 if (!pixels) {
7685 DCHECK_NE(disposition, kNullNotReachable);
7686 if (disposition == kNullAllowed)
7687 return true;
7688 SynthesizeGLError(GL_INVALID_VALUE, function_name, "no pixels");
7689 return false;
7690 }
7691
7692 if (!ValidateSettableTexFormat(function_name, format))
7693 return false;
7694
7695 auto pixelType = pixels->GetType();
7696
7697 switch (type) {
7698 case GL_BYTE:
7699 if (pixelType != DOMArrayBufferView::kTypeInt8) {
7700 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7701 "type BYTE but ArrayBufferView not Int8Array");
7702 return false;
7703 }
7704 break;
7705 case GL_UNSIGNED_BYTE:
7706 if (pixelType != DOMArrayBufferView::kTypeUint8 &&
7707 pixelType != DOMArrayBufferView::kTypeUint8Clamped) {
7708 SynthesizeGLError(
7709 GL_INVALID_OPERATION, function_name,
7710 "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array or "
7711 "Uint8ClampedArray");
7712 return false;
7713 }
7714 break;
7715 case GL_SHORT:
7716 if (pixelType != DOMArrayBufferView::kTypeInt16) {
7717 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7718 "type SHORT but ArrayBufferView not Int16Array");
7719 return false;
7720 }
7721 break;
7722 case GL_UNSIGNED_SHORT:
7723 case GL_UNSIGNED_SHORT_5_6_5:
7724 case GL_UNSIGNED_SHORT_4_4_4_4:
7725 case GL_UNSIGNED_SHORT_5_5_5_1:
7726 if (pixelType != DOMArrayBufferView::kTypeUint16) {
7727 SynthesizeGLError(
7728 GL_INVALID_OPERATION, function_name,
7729 "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
7730 return false;
7731 }
7732 break;
7733 case GL_INT:
7734 if (pixelType != DOMArrayBufferView::kTypeInt32) {
7735 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7736 "type INT but ArrayBufferView not Int32Array");
7737 return false;
7738 }
7739 break;
7740 case GL_UNSIGNED_INT:
7741 case GL_UNSIGNED_INT_2_10_10_10_REV:
7742 case GL_UNSIGNED_INT_10F_11F_11F_REV:
7743 case GL_UNSIGNED_INT_5_9_9_9_REV:
7744 case GL_UNSIGNED_INT_24_8:
7745 if (pixelType != DOMArrayBufferView::kTypeUint32) {
7746 SynthesizeGLError(
7747 GL_INVALID_OPERATION, function_name,
7748 "type UNSIGNED_INT but ArrayBufferView not Uint32Array");
7749 return false;
7750 }
7751 break;
7752 case GL_FLOAT: // OES_texture_float
7753 if (pixelType != DOMArrayBufferView::kTypeFloat32) {
7754 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7755 "type FLOAT but ArrayBufferView not Float32Array");
7756 return false;
7757 }
7758 break;
7759 case GL_HALF_FLOAT:
7760 case GL_HALF_FLOAT_OES: // OES_texture_half_float
7761 // As per the specification, ArrayBufferView should be null or a
7762 // Uint16Array when OES_texture_half_float is enabled.
7763 if (pixelType != DOMArrayBufferView::kTypeUint16) {
7764 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7765 "type HALF_FLOAT_OES but ArrayBufferView is not NULL "
7766 "and not Uint16Array");
7767 return false;
7768 }
7769 break;
7770 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
7771 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7772 "type FLOAT_32_UNSIGNED_INT_24_8_REV but "
7773 "ArrayBufferView is not NULL");
7774 return false;
7775 default:
7776 NOTREACHED();
7777 }
7778
7779 unsigned total_bytes_required, skip_bytes;
7780 GLenum error = WebGLImageConversion::ComputeImageSizeInBytes(
7781 format, type, width, height, depth,
7782 GetUnpackPixelStoreParams(tex_dimension), &total_bytes_required, nullptr,
7783 &skip_bytes);
7784 if (error != GL_NO_ERROR) {
7785 SynthesizeGLError(error, function_name, "invalid texture dimensions");
7786 return false;
7787 }
7788 base::CheckedNumeric<uint32_t> total = src_offset;
7789 total *= pixels->TypeSize();
7790 total += total_bytes_required;
7791 total += skip_bytes;
7792 if (!total.IsValid() ||
7793 pixels->byteLength() < static_cast<size_t>(total.ValueOrDie())) {
7794 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7795 "ArrayBufferView not big enough for request");
7796 return false;
7797 }
7798 return true;
7799 }
7800
ValidateCompressedTexFormat(const char * function_name,GLenum format)7801 bool WebGLRenderingContextBase::ValidateCompressedTexFormat(
7802 const char* function_name,
7803 GLenum format) {
7804 if (!compressed_texture_formats_.Contains(format)) {
7805 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid format");
7806 return false;
7807 }
7808 return true;
7809 }
7810
ValidateStencilOrDepthFunc(const char * function_name,GLenum func)7811 bool WebGLRenderingContextBase::ValidateStencilOrDepthFunc(
7812 const char* function_name,
7813 GLenum func) {
7814 switch (func) {
7815 case GL_NEVER:
7816 case GL_LESS:
7817 case GL_LEQUAL:
7818 case GL_GREATER:
7819 case GL_GEQUAL:
7820 case GL_EQUAL:
7821 case GL_NOTEQUAL:
7822 case GL_ALWAYS:
7823 return true;
7824 default:
7825 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid function");
7826 return false;
7827 }
7828 }
7829
PrintGLErrorToConsole(const String & message)7830 void WebGLRenderingContextBase::PrintGLErrorToConsole(const String& message) {
7831 if (!num_gl_errors_to_console_allowed_)
7832 return;
7833
7834 --num_gl_errors_to_console_allowed_;
7835 PrintWarningToConsole(message);
7836
7837 if (!num_gl_errors_to_console_allowed_)
7838 PrintWarningToConsole(
7839 "WebGL: too many errors, no more errors will be reported to the "
7840 "console for this context.");
7841
7842 return;
7843 }
7844
PrintWarningToConsole(const String & message)7845 void WebGLRenderingContextBase::PrintWarningToConsole(const String& message) {
7846 if (fast_call_.InFastCall()) {
7847 fast_call_.AddDeferredConsoleWarning(message);
7848 return;
7849 }
7850
7851 blink::ExecutionContext* context = Host()->GetTopExecutionContext();
7852 if (context && !context->IsContextDestroyed()) {
7853 context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
7854 mojom::ConsoleMessageSource::kRendering,
7855 mojom::ConsoleMessageLevel::kWarning, message));
7856 }
7857 }
7858
NotifyWebGLErrorOrWarning(const String & message)7859 void WebGLRenderingContextBase::NotifyWebGLErrorOrWarning(
7860 const String& message) {
7861 if (fast_call_.InFastCall()) {
7862 fast_call_.AddDeferredErrorOrWarningNotification(message);
7863 return;
7864 }
7865 probe::DidFireWebGLErrorOrWarning(canvas(), message);
7866 }
7867
NotifyWebGLError(const String & error_type)7868 void WebGLRenderingContextBase::NotifyWebGLError(const String& error_type) {
7869 if (fast_call_.InFastCall()) {
7870 fast_call_.AddDeferredErrorNotification(error_type);
7871 return;
7872 }
7873 probe::DidFireWebGLError(canvas(), error_type);
7874 }
7875
NotifyWebGLWarning()7876 void WebGLRenderingContextBase::NotifyWebGLWarning() {
7877 if (fast_call_.InFastCall()) {
7878 fast_call_.AddDeferredWarningNotification();
7879 return;
7880 }
7881 probe::DidFireWebGLWarning(canvas());
7882 }
7883
ValidateFramebufferFuncParameters(const char * function_name,GLenum target,GLenum attachment)7884 bool WebGLRenderingContextBase::ValidateFramebufferFuncParameters(
7885 const char* function_name,
7886 GLenum target,
7887 GLenum attachment) {
7888 if (!ValidateFramebufferTarget(target)) {
7889 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
7890 return false;
7891 }
7892 switch (attachment) {
7893 case GL_COLOR_ATTACHMENT0:
7894 case GL_DEPTH_ATTACHMENT:
7895 case GL_STENCIL_ATTACHMENT:
7896 case GL_DEPTH_STENCIL_ATTACHMENT:
7897 break;
7898 default:
7899 if ((ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()) &&
7900 attachment > GL_COLOR_ATTACHMENT0 &&
7901 attachment <
7902 static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + MaxColorAttachments()))
7903 break;
7904 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid attachment");
7905 return false;
7906 }
7907 return true;
7908 }
7909
ValidateBlendEquation(const char * function_name,GLenum mode)7910 bool WebGLRenderingContextBase::ValidateBlendEquation(const char* function_name,
7911 GLenum mode) {
7912 switch (mode) {
7913 case GL_FUNC_ADD:
7914 case GL_FUNC_SUBTRACT:
7915 case GL_FUNC_REVERSE_SUBTRACT:
7916 return true;
7917 case GL_MIN_EXT:
7918 case GL_MAX_EXT:
7919 if (ExtensionEnabled(kEXTBlendMinMaxName) || IsWebGL2())
7920 return true;
7921 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid mode");
7922 return false;
7923 default:
7924 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid mode");
7925 return false;
7926 }
7927 }
7928
ValidateBlendFuncFactors(const char * function_name,GLenum src,GLenum dst)7929 bool WebGLRenderingContextBase::ValidateBlendFuncFactors(
7930 const char* function_name,
7931 GLenum src,
7932 GLenum dst) {
7933 if (((src == GL_CONSTANT_COLOR || src == GL_ONE_MINUS_CONSTANT_COLOR) &&
7934 (dst == GL_CONSTANT_ALPHA || dst == GL_ONE_MINUS_CONSTANT_ALPHA)) ||
7935 ((dst == GL_CONSTANT_COLOR || dst == GL_ONE_MINUS_CONSTANT_COLOR) &&
7936 (src == GL_CONSTANT_ALPHA || src == GL_ONE_MINUS_CONSTANT_ALPHA))) {
7937 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7938 "incompatible src and dst");
7939 return false;
7940 }
7941 return true;
7942 }
7943
ValidateCapability(const char * function_name,GLenum cap)7944 bool WebGLRenderingContextBase::ValidateCapability(const char* function_name,
7945 GLenum cap) {
7946 switch (cap) {
7947 case GL_BLEND:
7948 case GL_CULL_FACE:
7949 case GL_DEPTH_TEST:
7950 case GL_DITHER:
7951 case GL_POLYGON_OFFSET_FILL:
7952 case GL_SAMPLE_ALPHA_TO_COVERAGE:
7953 case GL_SAMPLE_COVERAGE:
7954 case GL_SCISSOR_TEST:
7955 case GL_STENCIL_TEST:
7956 return true;
7957 default:
7958 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid capability");
7959 return false;
7960 }
7961 }
7962
ValidateUniformParameters(const char * function_name,const WebGLUniformLocation * location,void * v,GLsizei size,GLsizei required_min_size,GLuint src_offset,GLuint src_length)7963 bool WebGLRenderingContextBase::ValidateUniformParameters(
7964 const char* function_name,
7965 const WebGLUniformLocation* location,
7966 void* v,
7967 GLsizei size,
7968 GLsizei required_min_size,
7969 GLuint src_offset,
7970 GLuint src_length) {
7971 return ValidateUniformMatrixParameters(function_name, location, false, v,
7972 size, required_min_size, src_offset,
7973 src_length);
7974 }
7975
ValidateUniformMatrixParameters(const char * function_name,const WebGLUniformLocation * location,GLboolean transpose,DOMFloat32Array * v,GLsizei required_min_size,GLuint src_offset,size_t src_length)7976 bool WebGLRenderingContextBase::ValidateUniformMatrixParameters(
7977 const char* function_name,
7978 const WebGLUniformLocation* location,
7979 GLboolean transpose,
7980 DOMFloat32Array* v,
7981 GLsizei required_min_size,
7982 GLuint src_offset,
7983 size_t src_length) {
7984 if (!v) {
7985 SynthesizeGLError(GL_INVALID_VALUE, function_name, "no array");
7986 return false;
7987 }
7988 if (!base::CheckedNumeric<GLuint>(src_length).IsValid()) {
7989 SynthesizeGLError(GL_INVALID_VALUE, function_name,
7990 "src_length exceeds the maximum supported length");
7991 return false;
7992 }
7993 return ValidateUniformMatrixParameters(
7994 function_name, location, transpose, v->DataMaybeShared(), v->length(),
7995 required_min_size, src_offset, static_cast<GLuint>(src_length));
7996 }
7997
ValidateUniformMatrixParameters(const char * function_name,const WebGLUniformLocation * location,GLboolean transpose,void * v,size_t size,GLsizei required_min_size,GLuint src_offset,GLuint src_length)7998 bool WebGLRenderingContextBase::ValidateUniformMatrixParameters(
7999 const char* function_name,
8000 const WebGLUniformLocation* location,
8001 GLboolean transpose,
8002 void* v,
8003 size_t size,
8004 GLsizei required_min_size,
8005 GLuint src_offset,
8006 GLuint src_length) {
8007 DCHECK(size >= 0 && required_min_size > 0);
8008 if (!location)
8009 return false;
8010 if (location->Program() != current_program_) {
8011 SynthesizeGLError(GL_INVALID_OPERATION, function_name,
8012 "location is not from current program");
8013 return false;
8014 }
8015 if (!v) {
8016 SynthesizeGLError(GL_INVALID_VALUE, function_name, "no array");
8017 return false;
8018 }
8019 if (!base::CheckedNumeric<GLsizei>(size).IsValid()) {
8020 SynthesizeGLError(GL_INVALID_VALUE, function_name,
8021 "array exceeds the maximum supported size");
8022 return false;
8023 }
8024 if (transpose && !IsWebGL2()) {
8025 SynthesizeGLError(GL_INVALID_VALUE, function_name, "transpose not FALSE");
8026 return false;
8027 }
8028 if (src_offset >= static_cast<GLuint>(size)) {
8029 SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid srcOffset");
8030 return false;
8031 }
8032 GLsizei actual_size = static_cast<GLsizei>(size) - src_offset;
8033 if (src_length > 0) {
8034 if (src_length > static_cast<GLuint>(actual_size)) {
8035 SynthesizeGLError(GL_INVALID_VALUE, function_name,
8036 "invalid srcOffset + srcLength");
8037 return false;
8038 }
8039 actual_size = src_length;
8040 }
8041 if (actual_size < required_min_size || (actual_size % required_min_size)) {
8042 SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid size");
8043 return false;
8044 }
8045 return true;
8046 }
8047
ValidateBufferDataTarget(const char * function_name,GLenum target)8048 WebGLBuffer* WebGLRenderingContextBase::ValidateBufferDataTarget(
8049 const char* function_name,
8050 GLenum target) {
8051 WebGLBuffer* buffer = nullptr;
8052 switch (target) {
8053 case GL_ELEMENT_ARRAY_BUFFER:
8054 buffer = bound_vertex_array_object_->BoundElementArrayBuffer();
8055 break;
8056 case GL_ARRAY_BUFFER:
8057 buffer = bound_array_buffer_.Get();
8058 break;
8059 default:
8060 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
8061 return nullptr;
8062 }
8063 if (!buffer) {
8064 SynthesizeGLError(GL_INVALID_OPERATION, function_name, "no buffer");
8065 return nullptr;
8066 }
8067 return buffer;
8068 }
8069
ValidateBufferDataUsage(const char * function_name,GLenum usage)8070 bool WebGLRenderingContextBase::ValidateBufferDataUsage(
8071 const char* function_name,
8072 GLenum usage) {
8073 switch (usage) {
8074 case GL_STREAM_DRAW:
8075 case GL_STATIC_DRAW:
8076 case GL_DYNAMIC_DRAW:
8077 return true;
8078 default:
8079 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid usage");
8080 return false;
8081 }
8082 }
8083
RemoveBoundBuffer(WebGLBuffer * buffer)8084 void WebGLRenderingContextBase::RemoveBoundBuffer(WebGLBuffer* buffer) {
8085 if (bound_array_buffer_ == buffer)
8086 bound_array_buffer_ = nullptr;
8087
8088 bound_vertex_array_object_->UnbindBuffer(buffer);
8089 }
8090
ValidateHTMLImageElement(const SecurityOrigin * security_origin,const char * function_name,HTMLImageElement * image,ExceptionState & exception_state)8091 bool WebGLRenderingContextBase::ValidateHTMLImageElement(
8092 const SecurityOrigin* security_origin,
8093 const char* function_name,
8094 HTMLImageElement* image,
8095 ExceptionState& exception_state) {
8096 if (!image || !image->CachedImage()) {
8097 SynthesizeGLError(GL_INVALID_VALUE, function_name, "no image");
8098 return false;
8099 }
8100 const KURL& url = image->CachedImage()->GetResponse().CurrentRequestUrl();
8101 if (url.IsNull() || url.IsEmpty() || !url.IsValid()) {
8102 SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid image");
8103 return false;
8104 }
8105
8106 if (WouldTaintOrigin(image)) {
8107 exception_state.ThrowSecurityError(
8108 "The image element contains cross-origin data, and may not be loaded.");
8109 return false;
8110 }
8111 return true;
8112 }
8113
ValidateCanvasRenderingContextHost(const SecurityOrigin * security_origin,const char * function_name,CanvasRenderingContextHost * context_host,ExceptionState & exception_state)8114 bool WebGLRenderingContextBase::ValidateCanvasRenderingContextHost(
8115 const SecurityOrigin* security_origin,
8116 const char* function_name,
8117 CanvasRenderingContextHost* context_host,
8118 ExceptionState& exception_state) {
8119 if (!context_host || !context_host->IsPaintable()) {
8120 SynthesizeGLError(GL_INVALID_VALUE, function_name, "no canvas");
8121 return false;
8122 }
8123
8124 if (WouldTaintOrigin(context_host)) {
8125 exception_state.ThrowSecurityError("Tainted canvases may not be loaded.");
8126 return false;
8127 }
8128 return true;
8129 }
8130
ValidateHTMLVideoElement(const SecurityOrigin * security_origin,const char * function_name,HTMLVideoElement * video,ExceptionState & exception_state)8131 bool WebGLRenderingContextBase::ValidateHTMLVideoElement(
8132 const SecurityOrigin* security_origin,
8133 const char* function_name,
8134 HTMLVideoElement* video,
8135 ExceptionState& exception_state) {
8136 if (!video || !video->videoWidth() || !video->videoHeight()) {
8137 SynthesizeGLError(GL_INVALID_VALUE, function_name, "no video");
8138 return false;
8139 }
8140
8141 if (WouldTaintOrigin(video)) {
8142 exception_state.ThrowSecurityError(
8143 "The video element contains cross-origin data, and may not be loaded.");
8144 return false;
8145 }
8146 return true;
8147 }
8148
ValidateImageBitmap(const char * function_name,ImageBitmap * bitmap,ExceptionState & exception_state)8149 bool WebGLRenderingContextBase::ValidateImageBitmap(
8150 const char* function_name,
8151 ImageBitmap* bitmap,
8152 ExceptionState& exception_state) {
8153 if (bitmap->IsNeutered()) {
8154 SynthesizeGLError(GL_INVALID_VALUE, function_name,
8155 "The source data has been detached.");
8156 return false;
8157 }
8158 if (!bitmap->OriginClean()) {
8159 exception_state.ThrowSecurityError(
8160 "The ImageBitmap contains cross-origin data, and may not be loaded.");
8161 return false;
8162 }
8163 return true;
8164 }
8165
ValidateDrawArrays(const char * function_name)8166 bool WebGLRenderingContextBase::ValidateDrawArrays(const char* function_name) {
8167 if (isContextLost())
8168 return false;
8169
8170 if (!ValidateRenderingState(function_name)) {
8171 return false;
8172 }
8173
8174 const char* reason = "framebuffer incomplete";
8175 if (framebuffer_binding_ && framebuffer_binding_->CheckDepthStencilStatus(
8176 &reason) != GL_FRAMEBUFFER_COMPLETE) {
8177 SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, function_name, reason);
8178 return false;
8179 }
8180
8181 return true;
8182 }
8183
ValidateDrawElements(const char * function_name,GLenum type,int64_t offset)8184 bool WebGLRenderingContextBase::ValidateDrawElements(const char* function_name,
8185 GLenum type,
8186 int64_t offset) {
8187 if (isContextLost())
8188 return false;
8189
8190 if (type == GL_UNSIGNED_INT && !IsWebGL2() &&
8191 !ExtensionEnabled(kOESElementIndexUintName)) {
8192 SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid type");
8193 return false;
8194 }
8195
8196 if (!ValidateValueFitNonNegInt32(function_name, "offset", offset))
8197 return false;
8198
8199 if (!ValidateRenderingState(function_name)) {
8200 return false;
8201 }
8202
8203 const char* reason = "framebuffer incomplete";
8204 if (framebuffer_binding_ && framebuffer_binding_->CheckDepthStencilStatus(
8205 &reason) != GL_FRAMEBUFFER_COMPLETE) {
8206 SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, function_name, reason);
8207 return false;
8208 }
8209
8210 return true;
8211 }
8212
OnBeforeDrawCall()8213 void WebGLRenderingContextBase::OnBeforeDrawCall() {
8214 ClearIfComposited();
8215 MarkContextChanged(kCanvasChanged);
8216 }
8217
DispatchContextLostEvent(TimerBase *)8218 void WebGLRenderingContextBase::DispatchContextLostEvent(TimerBase*) {
8219 // WebXR spec: When the WebGL context is lost, set the xr compatible boolean
8220 // to false prior to firing the webglcontextlost event.
8221 xr_compatible_ = false;
8222
8223 WebGLContextEvent* event =
8224 WebGLContextEvent::Create(event_type_names::kWebglcontextlost, "");
8225 Host()->HostDispatchEvent(event);
8226 restore_allowed_ = event->defaultPrevented();
8227 if (restore_allowed_ && !is_hidden_) {
8228 if (auto_recovery_method_ == kAuto)
8229 restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
8230 }
8231
8232 if (!restore_allowed_) {
8233 // Per WebXR spec, reject the promise with an AbortError if the default
8234 // behavior wasn't prevented. CompleteXrCompatiblePromiseIfPending rejects
8235 // the promise if xr_compatible_ is false, which was set at the beginning of
8236 // this method.
8237 CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
8238 }
8239 }
8240
MaybeRestoreContext(TimerBase *)8241 void WebGLRenderingContextBase::MaybeRestoreContext(TimerBase*) {
8242 DCHECK(isContextLost());
8243
8244 // The rendering context is not restored unless the default behavior of the
8245 // webglcontextlost event was prevented earlier.
8246 //
8247 // Because of the way m_restoreTimer is set up for real vs. synthetic lost
8248 // context events, we don't have to worry about this test short-circuiting
8249 // the retry loop for real context lost events.
8250 if (!restore_allowed_)
8251 return;
8252
8253 if (canvas()) {
8254 LocalFrame* frame = canvas()->GetDocument().GetFrame();
8255 if (!frame)
8256 return;
8257
8258 bool blocked = false;
8259 mojo::Remote<mojom::blink::GpuDataManager> gpu_data_manager;
8260 Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
8261 gpu_data_manager.BindNewPipeAndPassReceiver());
8262 gpu_data_manager->Are3DAPIsBlockedForUrl(canvas()->GetDocument().Url(),
8263 &blocked);
8264 if (blocked)
8265 return;
8266
8267 Settings* settings = frame->GetSettings();
8268 if (settings && ((context_type_ == Platform::kWebGL1ContextType &&
8269 !settings->GetWebGL1Enabled()) ||
8270 (context_type_ == Platform::kWebGL2ContextType &&
8271 !settings->GetWebGL2Enabled()))) {
8272 return;
8273 }
8274 }
8275
8276 // Drawing buffer should have aready been destroyed during context loss to
8277 // ensure its resources were freed.
8278 DCHECK(!GetDrawingBuffer());
8279
8280 auto* execution_context = Host()->GetTopExecutionContext();
8281 Platform::ContextAttributes attributes = ToPlatformContextAttributes(
8282 CreationAttributes(), context_type_,
8283 SupportOwnOffscreenSurface(execution_context));
8284 Platform::GraphicsInfo gl_info;
8285 std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
8286 bool using_gpu_compositing;
8287 const auto& url = Host()->GetExecutionContextUrl();
8288
8289 if (IsMainThread()) {
8290 // Ask for gpu compositing mode when making the context. The context will be
8291 // lost if the mode changes.
8292 using_gpu_compositing = !Platform::Current()->IsGpuCompositingDisabled();
8293 context_provider =
8294 Platform::Current()->CreateOffscreenGraphicsContext3DProvider(
8295 attributes, url, &gl_info);
8296 } else {
8297 context_provider = CreateContextProviderOnWorkerThread(
8298 attributes, &gl_info, &using_gpu_compositing, url);
8299 }
8300 scoped_refptr<DrawingBuffer> buffer;
8301 if (context_provider && context_provider->BindToCurrentThread()) {
8302 // Construct a new drawing buffer with the new GL context.
8303 buffer =
8304 CreateDrawingBuffer(std::move(context_provider), using_gpu_compositing);
8305 // If DrawingBuffer::create() fails to allocate a fbo, |drawingBuffer| is
8306 // set to null.
8307 }
8308 if (!buffer) {
8309 if (context_lost_mode_ == kRealLostContext) {
8310 restore_timer_.StartOneShot(kDurationBetweenRestoreAttempts, FROM_HERE);
8311 } else {
8312 // This likely shouldn't happen but is the best way to report it to the
8313 // WebGL app.
8314 SynthesizeGLError(GL_INVALID_OPERATION, "", "error restoring context");
8315 }
8316 return;
8317 }
8318
8319 drawing_buffer_ = std::move(buffer);
8320 GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
8321 lost_context_errors_.clear();
8322 context_lost_mode_ = kNotLostContext;
8323 auto_recovery_method_ = kManual;
8324 restore_allowed_ = false;
8325 RemoveFromEvictedList(this);
8326
8327 SetupFlags();
8328 InitializeNewContext();
8329 MarkContextChanged(kCanvasContextChanged);
8330 WebGLContextEvent* event =
8331 WebGLContextEvent::Create(event_type_names::kWebglcontextrestored, "");
8332 Host()->HostDispatchEvent(event);
8333
8334 if (xr_compatible_) {
8335 CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kNoError);
8336 } else {
8337 CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
8338 }
8339 }
8340
EnsureNotNull(const String & text) const8341 String WebGLRenderingContextBase::EnsureNotNull(const String& text) const {
8342 if (text.IsNull())
8343 return WTF::g_empty_string;
8344 return text;
8345 }
8346
8347 WebGLRenderingContextBase::LRUCanvasResourceProviderCache::
LRUCanvasResourceProviderCache(wtf_size_t capacity)8348 LRUCanvasResourceProviderCache(wtf_size_t capacity)
8349 : resource_providers_(capacity) {}
8350
8351 CanvasResourceProvider* WebGLRenderingContextBase::
GetCanvasResourceProvider(const IntSize & size)8352 LRUCanvasResourceProviderCache::GetCanvasResourceProvider(
8353 const IntSize& size) {
8354 wtf_size_t i;
8355 for (i = 0; i < resource_providers_.size(); ++i) {
8356 CanvasResourceProvider* resource_provider = resource_providers_[i].get();
8357 if (!resource_provider)
8358 break;
8359 if (resource_provider->Size() != size)
8360 continue;
8361 BubbleToFront(i);
8362 return resource_provider;
8363 }
8364
8365 // TODO(fserb): why is this a BITMAP?
8366 std::unique_ptr<CanvasResourceProvider> temp(
8367 CanvasResourceProvider::CreateBitmapProvider(
8368 size, kLow_SkFilterQuality, CanvasColorParams(),
8369 CanvasResourceProvider::ShouldInitialize::kNo)); // TODO: should this
8370 // use the canvas's
8371
8372 if (!temp)
8373 return nullptr;
8374 i = std::min(resource_providers_.size() - 1, i);
8375 resource_providers_[i] = std::move(temp);
8376
8377 CanvasResourceProvider* resource_provider = resource_providers_[i].get();
8378 BubbleToFront(i);
8379 return resource_provider;
8380 }
8381
BubbleToFront(wtf_size_t idx)8382 void WebGLRenderingContextBase::LRUCanvasResourceProviderCache::BubbleToFront(
8383 wtf_size_t idx) {
8384 for (wtf_size_t i = idx; i > 0; --i)
8385 resource_providers_[i].swap(resource_providers_[i - 1]);
8386 }
8387
8388 namespace {
8389
GetErrorString(GLenum error)8390 String GetErrorString(GLenum error) {
8391 switch (error) {
8392 case GL_INVALID_ENUM:
8393 return "INVALID_ENUM";
8394 case GL_INVALID_VALUE:
8395 return "INVALID_VALUE";
8396 case GL_INVALID_OPERATION:
8397 return "INVALID_OPERATION";
8398 case GL_OUT_OF_MEMORY:
8399 return "OUT_OF_MEMORY";
8400 case GL_INVALID_FRAMEBUFFER_OPERATION:
8401 return "INVALID_FRAMEBUFFER_OPERATION";
8402 case GC3D_CONTEXT_LOST_WEBGL:
8403 return "CONTEXT_LOST_WEBGL";
8404 default:
8405 return String::Format("WebGL ERROR(0x%04X)", error);
8406 }
8407 }
8408
8409 } // namespace
8410
SynthesizeGLError(GLenum error,const char * function_name,const char * description,ConsoleDisplayPreference display)8411 void WebGLRenderingContextBase::SynthesizeGLError(
8412 GLenum error,
8413 const char* function_name,
8414 const char* description,
8415 ConsoleDisplayPreference display) {
8416 String error_type = GetErrorString(error);
8417 if (synthesized_errors_to_console_ && display == kDisplayInConsole) {
8418 String message = String("WebGL: ") + error_type + ": " +
8419 String(function_name) + ": " + String(description);
8420 PrintGLErrorToConsole(message);
8421 }
8422 if (!isContextLost()) {
8423 if (!synthetic_errors_.Contains(error))
8424 synthetic_errors_.push_back(error);
8425 } else {
8426 if (!lost_context_errors_.Contains(error))
8427 lost_context_errors_.push_back(error);
8428 }
8429 NotifyWebGLError(error_type);
8430 }
8431
EmitGLWarning(const char * function_name,const char * description)8432 void WebGLRenderingContextBase::EmitGLWarning(const char* function_name,
8433 const char* description) {
8434 if (synthesized_errors_to_console_) {
8435 String message =
8436 String("WebGL: ") + String(function_name) + ": " + String(description);
8437 PrintGLErrorToConsole(message);
8438 }
8439 NotifyWebGLWarning();
8440 }
8441
ApplyStencilTest()8442 void WebGLRenderingContextBase::ApplyStencilTest() {
8443 bool have_stencil_buffer = false;
8444
8445 if (framebuffer_binding_) {
8446 have_stencil_buffer = framebuffer_binding_->HasStencilBuffer();
8447 } else {
8448 have_stencil_buffer = !isContextLost() && CreationAttributes().stencil &&
8449 GetDrawingBuffer()->HasStencilBuffer();
8450 }
8451 EnableOrDisable(GL_STENCIL_TEST, stencil_enabled_ && have_stencil_buffer);
8452 }
8453
EnableOrDisable(GLenum capability,bool enable)8454 void WebGLRenderingContextBase::EnableOrDisable(GLenum capability,
8455 bool enable) {
8456 if (isContextLost())
8457 return;
8458 if (enable)
8459 ContextGL()->Enable(capability);
8460 else
8461 ContextGL()->Disable(capability);
8462 }
8463
ClampedCanvasSize() const8464 IntSize WebGLRenderingContextBase::ClampedCanvasSize() const {
8465 int width = Host()->Size().Width();
8466 int height = Host()->Size().Height();
8467 return IntSize(Clamp(width, 1, max_viewport_dims_[0]),
8468 Clamp(height, 1, max_viewport_dims_[1]));
8469 }
8470
MaxDrawBuffers()8471 GLint WebGLRenderingContextBase::MaxDrawBuffers() {
8472 if (isContextLost() ||
8473 !(ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()))
8474 return 0;
8475 if (!max_draw_buffers_)
8476 ContextGL()->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
8477 if (!max_color_attachments_)
8478 ContextGL()->GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT,
8479 &max_color_attachments_);
8480 // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
8481 return std::min(max_draw_buffers_, max_color_attachments_);
8482 }
8483
MaxColorAttachments()8484 GLint WebGLRenderingContextBase::MaxColorAttachments() {
8485 if (isContextLost() ||
8486 !(ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()))
8487 return 0;
8488 if (!max_color_attachments_)
8489 ContextGL()->GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT,
8490 &max_color_attachments_);
8491 return max_color_attachments_;
8492 }
8493
SetBackDrawBuffer(GLenum buf)8494 void WebGLRenderingContextBase::SetBackDrawBuffer(GLenum buf) {
8495 back_draw_buffer_ = buf;
8496 }
8497
SetFramebuffer(GLenum target,WebGLFramebuffer * buffer)8498 void WebGLRenderingContextBase::SetFramebuffer(GLenum target,
8499 WebGLFramebuffer* buffer) {
8500 if (buffer)
8501 buffer->SetHasEverBeenBound();
8502
8503 if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) {
8504 framebuffer_binding_ = buffer;
8505 ApplyStencilTest();
8506 }
8507 if (!buffer) {
8508 // Instead of binding fb 0, bind the drawing buffer.
8509 GetDrawingBuffer()->Bind(target);
8510 } else {
8511 ContextGL()->BindFramebuffer(target, buffer->Object());
8512 }
8513 }
8514
RestoreCurrentFramebuffer()8515 void WebGLRenderingContextBase::RestoreCurrentFramebuffer() {
8516 bindFramebuffer(GL_FRAMEBUFFER, framebuffer_binding_.Get());
8517 }
8518
RestoreCurrentTexture2D()8519 void WebGLRenderingContextBase::RestoreCurrentTexture2D() {
8520 bindTexture(GL_TEXTURE_2D,
8521 texture_units_[active_texture_unit_].texture2d_binding_.Get());
8522 }
8523
RestoreCurrentTextureCubeMap()8524 void WebGLRenderingContextBase::RestoreCurrentTextureCubeMap() {
8525 bindTexture(
8526 GL_TEXTURE_CUBE_MAP,
8527 texture_units_[active_texture_unit_].texture_cube_map_binding_.Get());
8528 }
8529
FindNewMaxNonDefaultTextureUnit()8530 void WebGLRenderingContextBase::FindNewMaxNonDefaultTextureUnit() {
8531 // Trace backwards from the current max to find the new max non-default
8532 // texture unit
8533 int start_index = one_plus_max_non_default_texture_unit_ - 1;
8534 for (int i = start_index; i >= 0; --i) {
8535 if (texture_units_[i].texture2d_binding_ ||
8536 texture_units_[i].texture_cube_map_binding_) {
8537 one_plus_max_non_default_texture_unit_ = i + 1;
8538 return;
8539 }
8540 }
8541 one_plus_max_non_default_texture_unit_ = 0;
8542 }
8543
Trace(blink::Visitor * visitor) const8544 void WebGLRenderingContextBase::TextureUnitState::Trace(
8545 blink::Visitor* visitor) const {
8546 visitor->Trace(texture2d_binding_);
8547 visitor->Trace(texture_cube_map_binding_);
8548 visitor->Trace(texture3d_binding_);
8549 visitor->Trace(texture2d_array_binding_);
8550 visitor->Trace(texture_video_image_binding_);
8551 }
8552
Trace(Visitor * visitor) const8553 void WebGLRenderingContextBase::Trace(Visitor* visitor) const {
8554 visitor->Trace(context_group_);
8555 visitor->Trace(bound_array_buffer_);
8556 visitor->Trace(default_vertex_array_object_);
8557 visitor->Trace(bound_vertex_array_object_);
8558 visitor->Trace(current_program_);
8559 visitor->Trace(framebuffer_binding_);
8560 visitor->Trace(renderbuffer_binding_);
8561 visitor->Trace(texture_units_);
8562 visitor->Trace(extensions_);
8563 visitor->Trace(make_xr_compatible_resolver_);
8564 CanvasRenderingContext::Trace(visitor);
8565 }
8566
ExternallyAllocatedBufferCountPerPixel()8567 int WebGLRenderingContextBase::ExternallyAllocatedBufferCountPerPixel() {
8568 if (isContextLost())
8569 return 0;
8570
8571 int buffer_count = 1;
8572 buffer_count *= 2; // WebGL's front and back color buffers.
8573 int samples = GetDrawingBuffer() ? GetDrawingBuffer()->SampleCount() : 0;
8574 WebGLContextAttributes* attribs = getContextAttributes();
8575 if (attribs) {
8576 // Handle memory from WebGL multisample and depth/stencil buffers.
8577 // It is enabled only in case of explicit resolve assuming that there
8578 // is no memory overhead for MSAA on tile-based GPU arch.
8579 if (attribs->antialias() && samples > 0 &&
8580 GetDrawingBuffer()->ExplicitResolveOfMultisampleData()) {
8581 if (attribs->depth() || attribs->stencil())
8582 buffer_count += samples; // depth/stencil multisample buffer
8583 buffer_count += samples; // color multisample buffer
8584 } else if (attribs->depth() || attribs->stencil()) {
8585 buffer_count += 1; // regular depth/stencil buffer
8586 }
8587 }
8588
8589 return buffer_count;
8590 }
8591
GetDrawingBuffer() const8592 DrawingBuffer* WebGLRenderingContextBase::GetDrawingBuffer() const {
8593 return drawing_buffer_.get();
8594 }
8595
ResetUnpackParameters()8596 void WebGLRenderingContextBase::ResetUnpackParameters() {
8597 if (unpack_alignment_ != 1)
8598 ContextGL()->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
8599 }
8600
RestoreUnpackParameters()8601 void WebGLRenderingContextBase::RestoreUnpackParameters() {
8602 if (unpack_alignment_ != 1)
8603 ContextGL()->PixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment_);
8604 }
8605
getHTMLOrOffscreenCanvas(HTMLCanvasElementOrOffscreenCanvas & result) const8606 void WebGLRenderingContextBase::getHTMLOrOffscreenCanvas(
8607 HTMLCanvasElementOrOffscreenCanvas& result) const {
8608 if (canvas()) {
8609 result.SetHTMLCanvasElement(static_cast<HTMLCanvasElement*>(Host()));
8610 } else {
8611 result.SetOffscreenCanvas(static_cast<OffscreenCanvas*>(Host()));
8612 }
8613 }
8614
addProgramCompletionQuery(WebGLProgram * program,GLuint query)8615 void WebGLRenderingContextBase::addProgramCompletionQuery(WebGLProgram* program,
8616 GLuint query) {
8617 auto old_query = program_completion_queries_.Get(program);
8618 if (old_query != program_completion_queries_.end()) {
8619 ContextGL()->DeleteQueriesEXT(1, &old_query->second);
8620 }
8621 program_completion_queries_.Put(program, query);
8622 if (program_completion_queries_.size() > kMaxProgramCompletionQueries) {
8623 auto oldest = program_completion_queries_.rbegin();
8624 ContextGL()->DeleteQueriesEXT(1, &oldest->second);
8625 program_completion_queries_.Erase(oldest);
8626 }
8627 }
8628
clearProgramCompletionQueries()8629 void WebGLRenderingContextBase::clearProgramCompletionQueries() {
8630 for (auto query : program_completion_queries_) {
8631 ContextGL()->DeleteQueriesEXT(1, &query.second);
8632 }
8633 program_completion_queries_.Clear();
8634 }
8635
checkProgramCompletionQueryAvailable(WebGLProgram * program,bool * completed)8636 bool WebGLRenderingContextBase::checkProgramCompletionQueryAvailable(
8637 WebGLProgram* program,
8638 bool* completed) {
8639 GLuint id = 0;
8640 auto found = program_completion_queries_.Get(program);
8641 if (found != program_completion_queries_.end()) {
8642 id = found->second;
8643 GLuint available;
8644 ContextGL()->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_AVAILABLE,
8645 &available);
8646 if (available) {
8647 GLuint result = 0u;
8648 ContextGL()->GetQueryObjectuivEXT(id, GL_QUERY_RESULT, &result);
8649 program->setLinkStatus(result);
8650 }
8651 *completed = (available == GL_TRUE);
8652 return true;
8653 }
8654 return false;
8655 }
8656 } // namespace blink
8657