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 "config.h"
27 #include "core/html/canvas/WebGLRenderingContextBase.h"
28
29 #include "bindings/core/v8/ExceptionMessages.h"
30 #include "bindings/core/v8/ExceptionState.h"
31 #include "core/dom/ExceptionCode.h"
32 #include "core/fetch/ImageResource.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/frame/Settings.h"
35 #include "core/html/HTMLCanvasElement.h"
36 #include "core/html/HTMLImageElement.h"
37 #include "core/html/HTMLVideoElement.h"
38 #include "core/html/ImageData.h"
39 #include "core/html/canvas/ANGLEInstancedArrays.h"
40 #include "core/html/canvas/EXTBlendMinMax.h"
41 #include "core/html/canvas/EXTFragDepth.h"
42 #include "core/html/canvas/EXTShaderTextureLOD.h"
43 #include "core/html/canvas/EXTTextureFilterAnisotropic.h"
44 #include "core/html/canvas/OESElementIndexUint.h"
45 #include "core/html/canvas/OESStandardDerivatives.h"
46 #include "core/html/canvas/OESTextureFloat.h"
47 #include "core/html/canvas/OESTextureFloatLinear.h"
48 #include "core/html/canvas/OESTextureHalfFloat.h"
49 #include "core/html/canvas/OESTextureHalfFloatLinear.h"
50 #include "core/html/canvas/OESVertexArrayObject.h"
51 #include "core/html/canvas/WebGLActiveInfo.h"
52 #include "core/html/canvas/WebGLBuffer.h"
53 #include "core/html/canvas/WebGLCompressedTextureATC.h"
54 #include "core/html/canvas/WebGLCompressedTextureETC1.h"
55 #include "core/html/canvas/WebGLCompressedTexturePVRTC.h"
56 #include "core/html/canvas/WebGLCompressedTextureS3TC.h"
57 #include "core/html/canvas/WebGLContextAttributes.h"
58 #include "core/html/canvas/WebGLContextEvent.h"
59 #include "core/html/canvas/WebGLContextGroup.h"
60 #include "core/html/canvas/WebGLDebugRendererInfo.h"
61 #include "core/html/canvas/WebGLDebugShaders.h"
62 #include "core/html/canvas/WebGLDepthTexture.h"
63 #include "core/html/canvas/WebGLDrawBuffers.h"
64 #include "core/html/canvas/WebGLFramebuffer.h"
65 #include "core/html/canvas/WebGLLoseContext.h"
66 #include "core/html/canvas/WebGLProgram.h"
67 #include "core/html/canvas/WebGLRenderbuffer.h"
68 #include "core/html/canvas/WebGLShader.h"
69 #include "core/html/canvas/WebGLShaderPrecisionFormat.h"
70 #include "core/html/canvas/WebGLSharedWebGraphicsContext3D.h"
71 #include "core/html/canvas/WebGLTexture.h"
72 #include "core/html/canvas/WebGLUniformLocation.h"
73 #include "core/inspector/ConsoleMessage.h"
74 #include "core/inspector/InspectorInstrumentation.h"
75 #include "core/loader/FrameLoader.h"
76 #include "core/loader/FrameLoaderClient.h"
77 #include "core/rendering/RenderBox.h"
78 #include "platform/CheckedInt.h"
79 #include "platform/NotImplemented.h"
80 #include "platform/RuntimeEnabledFeatures.h"
81 #include "platform/geometry/IntSize.h"
82 #include "platform/graphics/GraphicsContext.h"
83 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
84 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h"
85 #include "platform/graphics/gpu/DrawingBuffer.h"
86 #include "public/platform/Platform.h"
87
88 #include "wtf/PassOwnPtr.h"
89 #include "wtf/Uint32Array.h"
90 #include "wtf/text/StringBuilder.h"
91
92 namespace blink {
93
94 const double secondsBetweenRestoreAttempts = 1.0;
95 const int maxGLErrorsAllowedToConsole = 256;
96 const unsigned maxGLActiveContexts = 16;
97
98 // FIXME: Oilpan: static vectors to heap allocated WebGLRenderingContextBase objects
99 // are kept here. This relies on the WebGLRenderingContextBase finalization to
100 // explicitly retire themselves from these vectors, but it'd be preferable if
101 // the references were traced as per usual.
activeContexts()102 Vector<WebGLRenderingContextBase*>& WebGLRenderingContextBase::activeContexts()
103 {
104 DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContextBase*>, activeContexts, ());
105 return activeContexts;
106 }
107
forciblyEvictedContexts()108 Vector<WebGLRenderingContextBase*>& WebGLRenderingContextBase::forciblyEvictedContexts()
109 {
110 DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContextBase*>, forciblyEvictedContexts, ());
111 return forciblyEvictedContexts;
112 }
113
forciblyLoseOldestContext(const String & reason)114 void WebGLRenderingContextBase::forciblyLoseOldestContext(const String& reason)
115 {
116 size_t candidateID = oldestContextIndex();
117 if (candidateID >= activeContexts().size())
118 return;
119
120 WebGLRenderingContextBase* candidate = activeContexts()[candidateID];
121
122 // This context could belong to a dead page and the last JavaScript reference has already
123 // been lost. Garbage collection might be triggered in the middle of this function, for
124 // example, printWarningToConsole() causes an upcall to JavaScript.
125 // Must make sure that the context is not deleted until the call stack unwinds.
126 RefPtrWillBeRawPtr<WebGLRenderingContextBase> protect(candidate);
127
128 candidate->printWarningToConsole(reason);
129 InspectorInstrumentation::didFireWebGLWarning(candidate->canvas());
130
131 // This will call deactivateContext once the context has actually been lost.
132 candidate->forceLostContext(WebGLRenderingContextBase::SyntheticLostContext, WebGLRenderingContextBase::WhenAvailable);
133 }
134
oldestContextIndex()135 size_t WebGLRenderingContextBase::oldestContextIndex()
136 {
137 if (!activeContexts().size())
138 return maxGLActiveContexts;
139
140 WebGLRenderingContextBase* candidate = activeContexts().first();
141 ASSERT(!candidate->isContextLost());
142 size_t candidateID = 0;
143 for (size_t ii = 1; ii < activeContexts().size(); ++ii) {
144 WebGLRenderingContextBase* context = activeContexts()[ii];
145 ASSERT(!context->isContextLost());
146 if (context->webContext()->lastFlushID() < candidate->webContext()->lastFlushID()) {
147 candidate = context;
148 candidateID = ii;
149 }
150 }
151
152 return candidateID;
153 }
154
oldestContextSize()155 IntSize WebGLRenderingContextBase::oldestContextSize()
156 {
157 IntSize size;
158
159 size_t candidateID = oldestContextIndex();
160 if (candidateID < activeContexts().size()) {
161 WebGLRenderingContextBase* candidate = activeContexts()[candidateID];
162 size.setWidth(candidate->drawingBufferWidth());
163 size.setHeight(candidate->drawingBufferHeight());
164 }
165
166 return size;
167 }
168
activateContext(WebGLRenderingContextBase * context)169 void WebGLRenderingContextBase::activateContext(WebGLRenderingContextBase* context)
170 {
171 unsigned removedContexts = 0;
172 while (activeContexts().size() >= maxGLActiveContexts && removedContexts < maxGLActiveContexts) {
173 forciblyLoseOldestContext("WARNING: Too many active WebGL contexts. Oldest context will be lost.");
174 removedContexts++;
175 }
176
177 ASSERT(!context->isContextLost());
178 if (!activeContexts().contains(context))
179 activeContexts().append(context);
180 }
181
deactivateContext(WebGLRenderingContextBase * context)182 void WebGLRenderingContextBase::deactivateContext(WebGLRenderingContextBase* context)
183 {
184 size_t position = activeContexts().find(context);
185 if (position != WTF::kNotFound)
186 activeContexts().remove(position);
187 }
188
addToEvictedList(WebGLRenderingContextBase * context)189 void WebGLRenderingContextBase::addToEvictedList(WebGLRenderingContextBase* context)
190 {
191 if (!forciblyEvictedContexts().contains(context))
192 forciblyEvictedContexts().append(context);
193 }
194
removeFromEvictedList(WebGLRenderingContextBase * context)195 void WebGLRenderingContextBase::removeFromEvictedList(WebGLRenderingContextBase* context)
196 {
197 size_t position = forciblyEvictedContexts().find(context);
198 if (position != WTF::kNotFound)
199 forciblyEvictedContexts().remove(position);
200 }
201
willDestroyContext(WebGLRenderingContextBase * context)202 void WebGLRenderingContextBase::willDestroyContext(WebGLRenderingContextBase* context)
203 {
204 removeFromEvictedList(context);
205 deactivateContext(context);
206
207 // Try to re-enable the oldest inactive contexts.
208 while(activeContexts().size() < maxGLActiveContexts && forciblyEvictedContexts().size()) {
209 WebGLRenderingContextBase* evictedContext = forciblyEvictedContexts().first();
210 if (!evictedContext->m_restoreAllowed) {
211 forciblyEvictedContexts().remove(0);
212 continue;
213 }
214
215 IntSize desiredSize = DrawingBuffer::adjustSize(evictedContext->clampedCanvasSize(), IntSize(), evictedContext->m_maxTextureSize);
216
217 // If there's room in the pixel budget for this context, restore it.
218 if (!desiredSize.isEmpty()) {
219 forciblyEvictedContexts().remove(0);
220 evictedContext->forceRestoreContext();
221 }
222 break;
223 }
224 }
225
226 class WebGLRenderingContextEvictionManager : public ContextEvictionManager {
227 public:
forciblyLoseOldestContext(const String & reason)228 void forciblyLoseOldestContext(const String& reason) {
229 WebGLRenderingContextBase::forciblyLoseOldestContext(reason);
230 };
oldestContextSize()231 IntSize oldestContextSize() {
232 return WebGLRenderingContextBase::oldestContextSize();
233 };
234 };
235
236 namespace {
237
238 class ScopedDrawingBufferBinder {
239 STACK_ALLOCATED();
240 public:
ScopedDrawingBufferBinder(DrawingBuffer * drawingBuffer,WebGLFramebuffer * framebufferBinding)241 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
242 : m_drawingBuffer(drawingBuffer)
243 , m_framebufferBinding(framebufferBinding)
244 {
245 // Commit DrawingBuffer if needed (e.g., for multisampling)
246 if (!m_framebufferBinding && m_drawingBuffer)
247 m_drawingBuffer->commit();
248 }
249
~ScopedDrawingBufferBinder()250 ~ScopedDrawingBufferBinder()
251 {
252 // Restore DrawingBuffer if needed
253 if (!m_framebufferBinding && m_drawingBuffer)
254 m_drawingBuffer->bind();
255 }
256
257 private:
258 DrawingBuffer* m_drawingBuffer;
259 RawPtrWillBeMember<WebGLFramebuffer> m_framebufferBinding;
260 };
261
objectOrZero(WebGLObject * object)262 Platform3DObject objectOrZero(WebGLObject* object)
263 {
264 return object ? object->object() : 0;
265 }
266
clamp(GLint value,GLint min,GLint max)267 GLint clamp(GLint value, GLint min, GLint max)
268 {
269 if (value < min)
270 value = min;
271 if (value > max)
272 value = max;
273 return value;
274 }
275
276 // Return true if a character belongs to the ASCII subset as defined in
277 // GLSL ES 1.0 spec section 3.1.
validateCharacter(unsigned char c)278 bool validateCharacter(unsigned char c)
279 {
280 // Printing characters are valid except " $ ` @ \ ' DEL.
281 if (c >= 32 && c <= 126
282 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
283 return true;
284 // Horizontal tab, line feed, vertical tab, form feed, carriage return
285 // are also valid.
286 if (c >= 9 && c <= 13)
287 return true;
288 return false;
289 }
290
isPrefixReserved(const String & name)291 bool isPrefixReserved(const String& name)
292 {
293 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
294 return true;
295 return false;
296 }
297
298 // Strips comments from shader text. This allows non-ASCII characters
299 // to be used in comments without potentially breaking OpenGL
300 // implementations not expecting characters outside the GLSL ES set.
301 class StripComments {
302 public:
StripComments(const String & str)303 StripComments(const String& str)
304 : m_parseState(BeginningOfLine)
305 , m_sourceString(str)
306 , m_length(str.length())
307 , m_position(0)
308 {
309 parse();
310 }
311
result()312 String result()
313 {
314 return m_builder.toString();
315 }
316
317 private:
hasMoreCharacters() const318 bool hasMoreCharacters() const
319 {
320 return (m_position < m_length);
321 }
322
parse()323 void parse()
324 {
325 while (hasMoreCharacters()) {
326 process(current());
327 // process() might advance the position.
328 if (hasMoreCharacters())
329 advance();
330 }
331 }
332
333 void process(UChar);
334
peek(UChar & character) const335 bool peek(UChar& character) const
336 {
337 if (m_position + 1 >= m_length)
338 return false;
339 character = m_sourceString[m_position + 1];
340 return true;
341 }
342
current()343 UChar current()
344 {
345 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
346 return m_sourceString[m_position];
347 }
348
advance()349 void advance()
350 {
351 ++m_position;
352 }
353
isNewline(UChar character)354 static bool isNewline(UChar character)
355 {
356 // Don't attempt to canonicalize newline related characters.
357 return (character == '\n' || character == '\r');
358 }
359
emit(UChar character)360 void emit(UChar character)
361 {
362 m_builder.append(character);
363 }
364
365 enum ParseState {
366 // Have not seen an ASCII non-whitespace character yet on
367 // this line. Possible that we might see a preprocessor
368 // directive.
369 BeginningOfLine,
370
371 // Have seen at least one ASCII non-whitespace character
372 // on this line.
373 MiddleOfLine,
374
375 // Handling a preprocessor directive. Passes through all
376 // characters up to the end of the line. Disables comment
377 // processing.
378 InPreprocessorDirective,
379
380 // Handling a single-line comment. The comment text is
381 // replaced with a single space.
382 InSingleLineComment,
383
384 // Handling a multi-line comment. Newlines are passed
385 // through to preserve line numbers.
386 InMultiLineComment
387 };
388
389 ParseState m_parseState;
390 String m_sourceString;
391 unsigned m_length;
392 unsigned m_position;
393 StringBuilder m_builder;
394 };
395
process(UChar c)396 void StripComments::process(UChar c)
397 {
398 if (isNewline(c)) {
399 // No matter what state we are in, pass through newlines
400 // so we preserve line numbers.
401 emit(c);
402
403 if (m_parseState != InMultiLineComment)
404 m_parseState = BeginningOfLine;
405
406 return;
407 }
408
409 UChar temp = 0;
410 switch (m_parseState) {
411 case BeginningOfLine:
412 if (WTF::isASCIISpace(c)) {
413 emit(c);
414 break;
415 }
416
417 if (c == '#') {
418 m_parseState = InPreprocessorDirective;
419 emit(c);
420 break;
421 }
422
423 // Transition to normal state and re-handle character.
424 m_parseState = MiddleOfLine;
425 process(c);
426 break;
427
428 case MiddleOfLine:
429 if (c == '/' && peek(temp)) {
430 if (temp == '/') {
431 m_parseState = InSingleLineComment;
432 emit(' ');
433 advance();
434 break;
435 }
436
437 if (temp == '*') {
438 m_parseState = InMultiLineComment;
439 // Emit the comment start in case the user has
440 // an unclosed comment and we want to later
441 // signal an error.
442 emit('/');
443 emit('*');
444 advance();
445 break;
446 }
447 }
448
449 emit(c);
450 break;
451
452 case InPreprocessorDirective:
453 // No matter what the character is, just pass it
454 // through. Do not parse comments in this state. This
455 // might not be the right thing to do long term, but it
456 // should handle the #error preprocessor directive.
457 emit(c);
458 break;
459
460 case InSingleLineComment:
461 // The newline code at the top of this function takes care
462 // of resetting our state when we get out of the
463 // single-line comment. Swallow all other characters.
464 break;
465
466 case InMultiLineComment:
467 if (c == '*' && peek(temp) && temp == '/') {
468 emit('*');
469 emit('/');
470 m_parseState = MiddleOfLine;
471 advance();
472 break;
473 }
474
475 // Swallow all other characters. Unclear whether we may
476 // want or need to just emit a space per character to try
477 // to preserve column numbers for debugging purposes.
478 break;
479 }
480 }
481 } // namespace anonymous
482
483 class ScopedTexture2DRestorer {
484 STACK_ALLOCATED();
485 public:
ScopedTexture2DRestorer(WebGLRenderingContextBase * context)486 explicit ScopedTexture2DRestorer(WebGLRenderingContextBase* context)
487 : m_context(context)
488 {
489 }
490
~ScopedTexture2DRestorer()491 ~ScopedTexture2DRestorer()
492 {
493 m_context->restoreCurrentTexture2D();
494 }
495
496 private:
497 RawPtrWillBeMember<WebGLRenderingContextBase> m_context;
498 };
499
500 class WebGLRenderingContextLostCallback FINAL : public NoBaseWillBeGarbageCollectedFinalized<WebGLRenderingContextLostCallback>, public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
501 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
502 public:
create(WebGLRenderingContextBase * context)503 static PassOwnPtrWillBeRawPtr<WebGLRenderingContextLostCallback> create(WebGLRenderingContextBase* context)
504 {
505 return adoptPtrWillBeNoop(new WebGLRenderingContextLostCallback(context));
506 }
507
~WebGLRenderingContextLostCallback()508 virtual ~WebGLRenderingContextLostCallback() { }
509
onContextLost()510 virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContextBase::RealLostContext, WebGLRenderingContextBase::Auto); }
511
trace(Visitor * visitor)512 void trace(Visitor* visitor)
513 {
514 visitor->trace(m_context);
515 }
516
517 private:
WebGLRenderingContextLostCallback(WebGLRenderingContextBase * context)518 explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* context)
519 : m_context(context) { }
520
521 RawPtrWillBeMember<WebGLRenderingContextBase> m_context;
522 };
523
524 class WebGLRenderingContextErrorMessageCallback FINAL : public NoBaseWillBeGarbageCollectedFinalized<WebGLRenderingContextErrorMessageCallback>, public blink::WebGraphicsContext3D::WebGraphicsErrorMessageCallback {
525 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
526 public:
create(WebGLRenderingContextBase * context)527 static PassOwnPtrWillBeRawPtr<WebGLRenderingContextErrorMessageCallback> create(WebGLRenderingContextBase* context)
528 {
529 return adoptPtrWillBeNoop(new WebGLRenderingContextErrorMessageCallback(context));
530 }
531
~WebGLRenderingContextErrorMessageCallback()532 virtual ~WebGLRenderingContextErrorMessageCallback() { }
533
onErrorMessage(const blink::WebString & message,blink::WGC3Dint)534 virtual void onErrorMessage(const blink::WebString& message, blink::WGC3Dint)
535 {
536 if (m_context->m_synthesizedErrorsToConsole)
537 m_context->printGLErrorToConsole(message);
538 InspectorInstrumentation::didFireWebGLErrorOrWarning(m_context->canvas(), message);
539 }
540
trace(Visitor * visitor)541 void trace(Visitor* visitor)
542 {
543 visitor->trace(m_context);
544 }
545
546 private:
WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase * context)547 explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* context)
548 : m_context(context) { }
549
550 RawPtrWillBeMember<WebGLRenderingContextBase> m_context;
551 };
552
WebGLRenderingContextBase(HTMLCanvasElement * passedCanvas,PassOwnPtr<blink::WebGraphicsContext3D> context,WebGLContextAttributes * requestedAttributes)553 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassOwnPtr<blink::WebGraphicsContext3D> context, WebGLContextAttributes* requestedAttributes)
554 : CanvasRenderingContext(passedCanvas)
555 , ActiveDOMObject(&passedCanvas->document())
556 , m_contextLostMode(NotLostContext)
557 , m_autoRecoveryMethod(Manual)
558 , m_dispatchContextLostEventTimer(this, &WebGLRenderingContextBase::dispatchContextLostEvent)
559 , m_restoreAllowed(false)
560 , m_restoreTimer(this, &WebGLRenderingContextBase::maybeRestoreContext)
561 , m_generatedImageCache(4)
562 , m_requestedAttributes(requestedAttributes->clone())
563 , m_synthesizedErrorsToConsole(true)
564 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
565 , m_multisamplingAllowed(false)
566 , m_multisamplingObserverRegistered(false)
567 , m_onePlusMaxNonDefaultTextureUnit(0)
568 , m_savingImage(false)
569 {
570 ASSERT(context);
571
572 m_contextGroup = WebGLContextGroup::create();
573 m_contextGroup->addContext(this);
574
575 m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
576 context->getIntegerv(GL_MAX_VIEWPORT_DIMS, m_maxViewportDims);
577
578 RefPtr<DrawingBuffer> buffer = createDrawingBuffer(context);
579 if (!buffer)
580 return;
581
582 #if ENABLE(OILPAN)
583 m_sharedWebGraphicsContext3D = WebGLSharedWebGraphicsContext3D::create(buffer.release());
584 #else
585 m_drawingBuffer = buffer.release();
586 #endif
587
588 drawingBuffer()->bind();
589 setupFlags();
590 initializeNewContext();
591 }
592
createDrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context)593 PassRefPtr<DrawingBuffer> WebGLRenderingContextBase::createDrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context)
594 {
595 RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager());
596
597 blink::WebGraphicsContext3D::Attributes attrs;
598 attrs.alpha = m_requestedAttributes->alpha();
599 attrs.depth = m_requestedAttributes->depth();
600 attrs.stencil = m_requestedAttributes->stencil();
601 attrs.antialias = m_requestedAttributes->antialias();
602 attrs.premultipliedAlpha = m_requestedAttributes->premultipliedAlpha();
603 DrawingBuffer::PreserveDrawingBuffer preserve = m_requestedAttributes->preserveDrawingBuffer() ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
604 return DrawingBuffer::create(context, clampedCanvasSize(), preserve, attrs, contextEvictionManager.release());
605 }
606
initializeNewContext()607 void WebGLRenderingContextBase::initializeNewContext()
608 {
609 ASSERT(!isContextLost());
610 m_needsUpdate = true;
611 m_markedCanvasDirty = false;
612 m_activeTextureUnit = 0;
613 m_packAlignment = 4;
614 m_unpackAlignment = 4;
615 m_unpackFlipY = false;
616 m_unpackPremultiplyAlpha = false;
617 m_unpackColorspaceConversion = GC3D_BROWSER_DEFAULT_WEBGL;
618 m_boundArrayBuffer = nullptr;
619 m_currentProgram = nullptr;
620 m_framebufferBinding = nullptr;
621 m_renderbufferBinding = nullptr;
622 m_depthMask = true;
623 m_stencilEnabled = false;
624 m_stencilMask = 0xFFFFFFFF;
625 m_stencilMaskBack = 0xFFFFFFFF;
626 m_stencilFuncRef = 0;
627 m_stencilFuncRefBack = 0;
628 m_stencilFuncMask = 0xFFFFFFFF;
629 m_stencilFuncMaskBack = 0xFFFFFFFF;
630 m_layerCleared = false;
631 m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
632
633 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
634 m_scissorEnabled = false;
635 m_clearDepth = 1;
636 m_clearStencil = 0;
637 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
638
639 GLint numCombinedTextureImageUnits = 0;
640 webContext()->getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
641 m_textureUnits.clear();
642 m_textureUnits.resize(numCombinedTextureImageUnits);
643
644 GLint numVertexAttribs = 0;
645 webContext()->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &numVertexAttribs);
646 m_maxVertexAttribs = numVertexAttribs;
647
648 m_maxTextureSize = 0;
649 webContext()->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
650 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
651 m_maxCubeMapTextureSize = 0;
652 webContext()->getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
653 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
654 m_maxRenderbufferSize = 0;
655 webContext()->getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
656
657 // These two values from EXT_draw_buffers are lazily queried.
658 m_maxDrawBuffers = 0;
659 m_maxColorAttachments = 0;
660
661 m_backDrawBuffer = GL_BACK;
662
663 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
664 addContextObject(m_defaultVertexArrayObject.get());
665 m_boundVertexArrayObject = m_defaultVertexArrayObject;
666
667 m_vertexAttribValue.resize(m_maxVertexAttribs);
668
669 createFallbackBlackTextures1x1();
670
671 webContext()->viewport(0, 0, drawingBufferWidth(), drawingBufferHeight());
672 webContext()->scissor(0, 0, drawingBufferWidth(), drawingBufferHeight());
673
674 m_contextLostCallbackAdapter = WebGLRenderingContextLostCallback::create(this);
675 m_errorMessageCallbackAdapter = WebGLRenderingContextErrorMessageCallback::create(this);
676
677 webContext()->setContextLostCallback(m_contextLostCallbackAdapter.get());
678 webContext()->setErrorMessageCallback(m_errorMessageCallbackAdapter.get());
679
680 // This ensures that the context has a valid "lastFlushID" and won't be mistakenly identified as the "least recently used" context.
681 webContext()->flush();
682
683 for (int i = 0; i < WebGLExtensionNameCount; ++i)
684 m_extensionEnabled[i] = false;
685
686 activateContext(this);
687 }
688
setupFlags()689 void WebGLRenderingContextBase::setupFlags()
690 {
691 ASSERT(drawingBuffer());
692 if (Page* p = canvas()->document().page()) {
693 m_synthesizedErrorsToConsole = p->settings().webGLErrorsToConsoleEnabled();
694
695 if (!m_multisamplingObserverRegistered && m_requestedAttributes->antialias()) {
696 m_multisamplingAllowed = drawingBuffer()->multisample();
697 p->addMultisamplingChangedObserver(this);
698 m_multisamplingObserverRegistered = true;
699 }
700 }
701
702 m_isGLES2NPOTStrict = !extensionsUtil()->isExtensionEnabled("GL_OES_texture_npot");
703 m_isDepthStencilSupported = extensionsUtil()->isExtensionEnabled("GL_OES_packed_depth_stencil");
704 }
705
addCompressedTextureFormat(GLenum format)706 void WebGLRenderingContextBase::addCompressedTextureFormat(GLenum format)
707 {
708 if (!m_compressedTextureFormats.contains(format))
709 m_compressedTextureFormats.append(format);
710 }
711
removeAllCompressedTextureFormats()712 void WebGLRenderingContextBase::removeAllCompressedTextureFormats()
713 {
714 m_compressedTextureFormats.clear();
715 }
716
717 // Helper function for V8 bindings to identify what version of WebGL a CanvasRenderingContext supports.
getWebGLVersion(const CanvasRenderingContext * context)718 unsigned WebGLRenderingContextBase::getWebGLVersion(const CanvasRenderingContext* context)
719 {
720 if (!context->is3d())
721 return 0;
722 return static_cast<const WebGLRenderingContextBase*>(context)->version();
723 }
724
~WebGLRenderingContextBase()725 WebGLRenderingContextBase::~WebGLRenderingContextBase()
726 {
727 #if !ENABLE(OILPAN)
728 // Remove all references to WebGLObjects so if they are the last reference
729 // they will be freed before the last context is removed from the context group.
730 m_boundArrayBuffer = nullptr;
731 m_defaultVertexArrayObject = nullptr;
732 m_boundVertexArrayObject = nullptr;
733 m_vertexAttrib0Buffer = nullptr;
734 m_currentProgram = nullptr;
735 m_framebufferBinding = nullptr;
736 m_renderbufferBinding = nullptr;
737
738 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
739 m_textureUnits[i].m_texture2DBinding = nullptr;
740 m_textureUnits[i].m_textureCubeMapBinding = nullptr;
741 }
742
743 m_blackTexture2D = nullptr;
744 m_blackTextureCubeMap = nullptr;
745
746 detachAndRemoveAllObjects();
747
748 // Release all extensions now.
749 m_extensions.clear();
750 #endif
751
752 // Context must be removed from the group prior to the destruction of the
753 // WebGraphicsContext3D, otherwise shared objects may not be properly deleted.
754 m_contextGroup->removeContext(this);
755
756 destroyContext();
757
758 #if !ENABLE(OILPAN)
759 if (m_multisamplingObserverRegistered)
760 if (Page* page = canvas()->document().page())
761 page->removeMultisamplingChangedObserver(this);
762 #endif
763
764 willDestroyContext(this);
765 }
766
destroyContext()767 void WebGLRenderingContextBase::destroyContext()
768 {
769 if (!drawingBuffer())
770 return;
771
772 m_extensionsUtil.clear();
773
774 webContext()->setContextLostCallback(0);
775 webContext()->setErrorMessageCallback(0);
776
777 ASSERT(drawingBuffer());
778 #if ENABLE(OILPAN)
779 // The DrawingBuffer ref pointers are cleared, but the
780 // WebGLSharedWebGraphicsContext3D object will hold onto the
781 // DrawingBuffer for as long as needed (== until all
782 // context objects have been finalized), at which point
783 // DrawingBuffer destruction happens.
784 m_sharedWebGraphicsContext3D.clear();
785 #else
786 m_drawingBuffer->beginDestruction();
787 m_drawingBuffer.clear();
788 #endif
789 }
790
markContextChanged(ContentChangeType changeType)791 void WebGLRenderingContextBase::markContextChanged(ContentChangeType changeType)
792 {
793 if (m_framebufferBinding || isContextLost())
794 return;
795
796 drawingBuffer()->markContentsChanged();
797
798 m_layerCleared = false;
799 RenderBox* renderBox = canvas()->renderBox();
800 if (renderBox && renderBox->hasAcceleratedCompositing()) {
801 m_markedCanvasDirty = true;
802 canvas()->clearCopiedImage();
803 renderBox->contentChanged(changeType);
804 } else {
805 if (!m_markedCanvasDirty) {
806 m_markedCanvasDirty = true;
807 canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
808 }
809 }
810 }
811
clearIfComposited(GLbitfield mask)812 bool WebGLRenderingContextBase::clearIfComposited(GLbitfield mask)
813 {
814 if (isContextLost())
815 return false;
816
817 if (!drawingBuffer()->layerComposited() || m_layerCleared
818 || m_requestedAttributes->preserveDrawingBuffer() || (mask && m_framebufferBinding))
819 return false;
820
821 RefPtrWillBeRawPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
822
823 // Determine if it's possible to combine the clear the user asked for and this clear.
824 bool combinedClear = mask && !m_scissorEnabled;
825
826 webContext()->disable(GL_SCISSOR_TEST);
827 if (combinedClear && (mask & GL_COLOR_BUFFER_BIT)) {
828 webContext()->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
829 m_colorMask[1] ? m_clearColor[1] : 0,
830 m_colorMask[2] ? m_clearColor[2] : 0,
831 m_colorMask[3] ? m_clearColor[3] : 0);
832 } else {
833 webContext()->clearColor(0, 0, 0, 0);
834 }
835 webContext()->colorMask(true, true, true, true);
836 GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
837 if (contextAttributes->depth()) {
838 if (!combinedClear || !m_depthMask || !(mask & GL_DEPTH_BUFFER_BIT))
839 webContext()->clearDepth(1.0f);
840 clearMask |= GL_DEPTH_BUFFER_BIT;
841 webContext()->depthMask(true);
842 }
843 if (contextAttributes->stencil()) {
844 if (combinedClear && (mask & GL_STENCIL_BUFFER_BIT))
845 webContext()->clearStencil(m_clearStencil & m_stencilMask);
846 else
847 webContext()->clearStencil(0);
848 clearMask |= GL_STENCIL_BUFFER_BIT;
849 webContext()->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
850 }
851
852 drawingBuffer()->clearFramebuffers(clearMask);
853
854 restoreStateAfterClear();
855 if (m_framebufferBinding)
856 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
857 m_layerCleared = true;
858
859 return combinedClear;
860 }
861
restoreStateAfterClear()862 void WebGLRenderingContextBase::restoreStateAfterClear()
863 {
864 if (isContextLost())
865 return;
866
867 // Restore the state that the context set.
868 if (m_scissorEnabled)
869 webContext()->enable(GL_SCISSOR_TEST);
870 webContext()->clearColor(m_clearColor[0], m_clearColor[1],
871 m_clearColor[2], m_clearColor[3]);
872 webContext()->colorMask(m_colorMask[0], m_colorMask[1],
873 m_colorMask[2], m_colorMask[3]);
874 webContext()->clearDepth(m_clearDepth);
875 webContext()->clearStencil(m_clearStencil);
876 webContext()->stencilMaskSeparate(GL_FRONT, m_stencilMask);
877 webContext()->depthMask(m_depthMask);
878 }
879
markLayerComposited()880 void WebGLRenderingContextBase::markLayerComposited()
881 {
882 if (!isContextLost())
883 drawingBuffer()->markLayerComposited();
884 }
885
setIsHidden(bool hidden)886 void WebGLRenderingContextBase::setIsHidden(bool hidden)
887 {
888 if (drawingBuffer())
889 drawingBuffer()->setIsHidden(hidden);
890 }
891
paintRenderingResultsToCanvas()892 void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
893 {
894 if (isContextLost()) {
895 canvas()->clearPresentationCopy();
896 return;
897 }
898
899 if (canvas()->document().printing())
900 canvas()->clearPresentationCopy();
901
902 // Until the canvas is written to by the application, the clear that
903 // happened after it was composited should be ignored by the compositor.
904 if (drawingBuffer()->layerComposited() && !m_requestedAttributes->preserveDrawingBuffer()) {
905 drawingBuffer()->paintCompositedResultsToCanvas(canvas()->buffer());
906
907 canvas()->makePresentationCopy();
908 } else
909 canvas()->clearPresentationCopy();
910
911 clearIfComposited();
912
913 if (!m_markedCanvasDirty && !m_layerCleared)
914 return;
915
916 canvas()->clearCopiedImage();
917 m_markedCanvasDirty = false;
918
919 ScopedTexture2DRestorer restorer(this);
920
921 drawingBuffer()->commit();
922 if (!canvas()->buffer()->copyRenderingResultsFromDrawingBuffer(drawingBuffer(), m_savingImage)) {
923 canvas()->ensureUnacceleratedImageBuffer();
924 if (canvas()->hasImageBuffer())
925 drawingBuffer()->paintRenderingResultsToCanvas(canvas()->buffer());
926 }
927
928 if (m_framebufferBinding)
929 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
930 else
931 drawingBuffer()->bind();
932 }
933
paintRenderingResultsToImageData()934 PassRefPtrWillBeRawPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData()
935 {
936 if (isContextLost())
937 return nullptr;
938
939 clearIfComposited();
940 drawingBuffer()->commit();
941 int width, height;
942 RefPtr<Uint8ClampedArray> imageDataPixels = drawingBuffer()->paintRenderingResultsToImageData(width, height);
943 if (!imageDataPixels)
944 return nullptr;
945
946 if (m_framebufferBinding)
947 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
948 else
949 drawingBuffer()->bind();
950
951 return ImageData::create(IntSize(width, height), imageDataPixels);
952 }
953
reshape(int width,int height)954 void WebGLRenderingContextBase::reshape(int width, int height)
955 {
956 if (isContextLost())
957 return;
958
959 // This is an approximation because at WebGLRenderingContextBase level we don't
960 // know if the underlying FBO uses textures or renderbuffers.
961 GLint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
962 // Limit drawing buffer size to 4k to avoid memory exhaustion.
963 const int sizeUpperLimit = 4096;
964 maxSize = std::min(maxSize, sizeUpperLimit);
965 GLint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
966 GLint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
967 width = clamp(width, 1, maxWidth);
968 height = clamp(height, 1, maxHeight);
969
970 if (m_needsUpdate) {
971 RenderBox* renderBox = canvas()->renderBox();
972 if (renderBox && renderBox->hasAcceleratedCompositing())
973 renderBox->contentChanged(CanvasChanged);
974 m_needsUpdate = false;
975 }
976
977 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
978 // clear (and this matches what reshape will do).
979 drawingBuffer()->reset(IntSize(width, height));
980 restoreStateAfterClear();
981
982 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
983 webContext()->bindRenderbuffer(GL_RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
984 if (m_framebufferBinding)
985 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
986 }
987
drawingBufferWidth() const988 int WebGLRenderingContextBase::drawingBufferWidth() const
989 {
990 return isContextLost() ? 0 : drawingBuffer()->size().width();
991 }
992
drawingBufferHeight() const993 int WebGLRenderingContextBase::drawingBufferHeight() const
994 {
995 return isContextLost() ? 0 : drawingBuffer()->size().height();
996 }
997
sizeInBytes(GLenum type)998 unsigned WebGLRenderingContextBase::sizeInBytes(GLenum type)
999 {
1000 switch (type) {
1001 case GL_BYTE:
1002 return sizeof(GLbyte);
1003 case GL_UNSIGNED_BYTE:
1004 return sizeof(GLubyte);
1005 case GL_SHORT:
1006 return sizeof(GLshort);
1007 case GL_UNSIGNED_SHORT:
1008 return sizeof(GLushort);
1009 case GL_INT:
1010 return sizeof(GLint);
1011 case GL_UNSIGNED_INT:
1012 return sizeof(GLuint);
1013 case GL_FLOAT:
1014 return sizeof(GLfloat);
1015 }
1016 ASSERT_NOT_REACHED();
1017 return 0;
1018 }
1019
activeTexture(GLenum texture)1020 void WebGLRenderingContextBase::activeTexture(GLenum texture)
1021 {
1022 if (isContextLost())
1023 return;
1024 if (texture - GL_TEXTURE0 >= m_textureUnits.size()) {
1025 synthesizeGLError(GL_INVALID_ENUM, "activeTexture", "texture unit out of range");
1026 return;
1027 }
1028 m_activeTextureUnit = texture - GL_TEXTURE0;
1029 webContext()->activeTexture(texture);
1030
1031 drawingBuffer()->setActiveTextureUnit(texture);
1032
1033 }
1034
attachShader(WebGLProgram * program,WebGLShader * shader)1035 void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader)
1036 {
1037 if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
1038 return;
1039 if (!program->attachShader(shader)) {
1040 synthesizeGLError(GL_INVALID_OPERATION, "attachShader", "shader attachment already has shader");
1041 return;
1042 }
1043 webContext()->attachShader(objectOrZero(program), objectOrZero(shader));
1044 shader->onAttached();
1045 }
1046
bindAttribLocation(WebGLProgram * program,GLuint index,const String & name)1047 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GLuint index, const String& name)
1048 {
1049 if (isContextLost() || !validateWebGLObject("bindAttribLocation", program))
1050 return;
1051 if (!validateLocationLength("bindAttribLocation", name))
1052 return;
1053 if (!validateString("bindAttribLocation", name))
1054 return;
1055 if (isPrefixReserved(name)) {
1056 synthesizeGLError(GL_INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
1057 return;
1058 }
1059 if (index >= m_maxVertexAttribs) {
1060 synthesizeGLError(GL_INVALID_VALUE, "bindAttribLocation", "index out of range");
1061 return;
1062 }
1063 webContext()->bindAttribLocation(objectOrZero(program), index, name.utf8().data());
1064 }
1065
checkObjectToBeBound(const char * functionName,WebGLObject * object,bool & deleted)1066 bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
1067 {
1068 deleted = false;
1069 if (isContextLost())
1070 return false;
1071 if (object) {
1072 if (!object->validate(contextGroup(), this)) {
1073 synthesizeGLError(GL_INVALID_OPERATION, functionName, "object not from this context");
1074 return false;
1075 }
1076 deleted = !object->object();
1077 }
1078 return true;
1079 }
1080
bindBuffer(GLenum target,WebGLBuffer * buffer)1081 void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer)
1082 {
1083 bool deleted;
1084 if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
1085 return;
1086 if (deleted)
1087 buffer = 0;
1088 if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
1089 synthesizeGLError(GL_INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
1090 return;
1091 }
1092 if (target == GL_ARRAY_BUFFER)
1093 m_boundArrayBuffer = buffer;
1094 else if (target == GL_ELEMENT_ARRAY_BUFFER)
1095 m_boundVertexArrayObject->setElementArrayBuffer(buffer);
1096 else {
1097 synthesizeGLError(GL_INVALID_ENUM, "bindBuffer", "invalid target");
1098 return;
1099 }
1100
1101 webContext()->bindBuffer(target, objectOrZero(buffer));
1102 if (buffer)
1103 buffer->setTarget(target);
1104 }
1105
bindFramebuffer(GLenum target,WebGLFramebuffer * buffer)1106 void WebGLRenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* buffer)
1107 {
1108 bool deleted;
1109 if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
1110 return;
1111 if (deleted)
1112 buffer = 0;
1113 if (target != GL_FRAMEBUFFER) {
1114 synthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target");
1115 return;
1116 }
1117 m_framebufferBinding = buffer;
1118 drawingBuffer()->setFramebufferBinding(objectOrZero(m_framebufferBinding.get()));
1119 if (!m_framebufferBinding) {
1120 // Instead of binding fb 0, bind the drawing buffer.
1121 drawingBuffer()->bind();
1122 } else {
1123 webContext()->bindFramebuffer(target, objectOrZero(buffer));
1124 }
1125 if (buffer)
1126 buffer->setHasEverBeenBound();
1127 applyStencilTest();
1128 }
1129
bindRenderbuffer(GLenum target,WebGLRenderbuffer * renderBuffer)1130 void WebGLRenderingContextBase::bindRenderbuffer(GLenum target, WebGLRenderbuffer* renderBuffer)
1131 {
1132 bool deleted;
1133 if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
1134 return;
1135 if (deleted)
1136 renderBuffer = 0;
1137 if (target != GL_RENDERBUFFER) {
1138 synthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target");
1139 return;
1140 }
1141 m_renderbufferBinding = renderBuffer;
1142 webContext()->bindRenderbuffer(target, objectOrZero(renderBuffer));
1143 if (renderBuffer)
1144 renderBuffer->setHasEverBeenBound();
1145 }
1146
bindTexture(GLenum target,WebGLTexture * texture)1147 void WebGLRenderingContextBase::bindTexture(GLenum target, WebGLTexture* texture)
1148 {
1149 bool deleted;
1150 if (!checkObjectToBeBound("bindTexture", texture, deleted))
1151 return;
1152 if (deleted)
1153 texture = 0;
1154 if (texture && texture->getTarget() && texture->getTarget() != target) {
1155 synthesizeGLError(GL_INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
1156 return;
1157 }
1158 GLint maxLevel = 0;
1159 if (target == GL_TEXTURE_2D) {
1160 m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
1161 maxLevel = m_maxTextureLevel;
1162
1163 if (!m_activeTextureUnit)
1164 drawingBuffer()->setTexture2DBinding(objectOrZero(texture));
1165
1166 } else if (target == GL_TEXTURE_CUBE_MAP) {
1167 m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
1168 maxLevel = m_maxCubeMapTextureLevel;
1169 } else {
1170 synthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target");
1171 return;
1172 }
1173
1174 webContext()->bindTexture(target, objectOrZero(texture));
1175 if (texture) {
1176 texture->setTarget(target, maxLevel);
1177 m_onePlusMaxNonDefaultTextureUnit = max(m_activeTextureUnit + 1, m_onePlusMaxNonDefaultTextureUnit);
1178 } else {
1179 // If the disabled index is the current maximum, trace backwards to find the new max enabled texture index
1180 if (m_onePlusMaxNonDefaultTextureUnit == m_activeTextureUnit + 1) {
1181 findNewMaxNonDefaultTextureUnit();
1182 }
1183 }
1184
1185 // Note: previously we used to automatically set the TEXTURE_WRAP_R
1186 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
1187 // ES 2.0 doesn't expose this flag (a bug in the specification) and
1188 // otherwise the application has no control over the seams in this
1189 // dimension. However, it appears that supporting this properly on all
1190 // platforms is fairly involved (will require a HashMap from texture ID
1191 // in all ports), and we have not had any complaints, so the logic has
1192 // been removed.
1193
1194 }
1195
blendColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)1196 void WebGLRenderingContextBase::blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
1197 {
1198 if (isContextLost())
1199 return;
1200 webContext()->blendColor(red, green, blue, alpha);
1201 }
1202
blendEquation(GLenum mode)1203 void WebGLRenderingContextBase::blendEquation(GLenum mode)
1204 {
1205 if (isContextLost() || !validateBlendEquation("blendEquation", mode))
1206 return;
1207 webContext()->blendEquation(mode);
1208 }
1209
blendEquationSeparate(GLenum modeRGB,GLenum modeAlpha)1210 void WebGLRenderingContextBase::blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
1211 {
1212 if (isContextLost() || !validateBlendEquation("blendEquationSeparate", modeRGB) || !validateBlendEquation("blendEquationSeparate", modeAlpha))
1213 return;
1214 webContext()->blendEquationSeparate(modeRGB, modeAlpha);
1215 }
1216
1217
blendFunc(GLenum sfactor,GLenum dfactor)1218 void WebGLRenderingContextBase::blendFunc(GLenum sfactor, GLenum dfactor)
1219 {
1220 if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1221 return;
1222 webContext()->blendFunc(sfactor, dfactor);
1223 }
1224
blendFuncSeparate(GLenum srcRGB,GLenum dstRGB,GLenum srcAlpha,GLenum dstAlpha)1225 void WebGLRenderingContextBase::blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
1226 {
1227 // Note: Alpha does not have the same restrictions as RGB.
1228 if (isContextLost() || !validateBlendFuncFactors("blendFuncSeparate", srcRGB, dstRGB))
1229 return;
1230 webContext()->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1231 }
1232
bufferDataImpl(GLenum target,long long size,const void * data,GLenum usage)1233 void WebGLRenderingContextBase::bufferDataImpl(GLenum target, long long size, const void* data, GLenum usage)
1234 {
1235 WebGLBuffer* buffer = validateBufferDataTarget("bufferData", target);
1236 if (!buffer)
1237 return;
1238
1239 switch (usage) {
1240 case GL_STREAM_DRAW:
1241 case GL_STATIC_DRAW:
1242 case GL_DYNAMIC_DRAW:
1243 break;
1244 default:
1245 synthesizeGLError(GL_INVALID_ENUM, "bufferData", "invalid usage");
1246 return;
1247 }
1248
1249 if (!validateValueFitNonNegInt32("bufferData", "size", size))
1250 return;
1251
1252 webContext()->bufferData(target, static_cast<GLsizeiptr>(size), data, usage);
1253 }
1254
bufferData(GLenum target,long long size,GLenum usage)1255 void WebGLRenderingContextBase::bufferData(GLenum target, long long size, GLenum usage)
1256 {
1257 if (isContextLost())
1258 return;
1259 if (!size) {
1260 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "size == 0");
1261 return;
1262 }
1263 bufferDataImpl(target, size, 0, usage);
1264 }
1265
bufferData(GLenum target,ArrayBuffer * data,GLenum usage)1266 void WebGLRenderingContextBase::bufferData(GLenum target, ArrayBuffer* data, GLenum usage)
1267 {
1268 if (isContextLost())
1269 return;
1270 if (!data) {
1271 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data");
1272 return;
1273 }
1274 bufferDataImpl(target, data->byteLength(), data->data(), usage);
1275 }
1276
bufferData(GLenum target,ArrayBufferView * data,GLenum usage)1277 void WebGLRenderingContextBase::bufferData(GLenum target, ArrayBufferView* data, GLenum usage)
1278 {
1279 if (isContextLost())
1280 return;
1281 if (!data) {
1282 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data");
1283 return;
1284 }
1285 bufferDataImpl(target, data->byteLength(), data->baseAddress(), usage);
1286 }
1287
bufferSubDataImpl(GLenum target,long long offset,GLsizeiptr size,const void * data)1288 void WebGLRenderingContextBase::bufferSubDataImpl(GLenum target, long long offset, GLsizeiptr size, const void* data)
1289 {
1290 WebGLBuffer* buffer = validateBufferDataTarget("bufferSubData", target);
1291 if (!buffer)
1292 return;
1293 if (!validateValueFitNonNegInt32("bufferSubData", "offset", offset))
1294 return;
1295 if (!data)
1296 return;
1297
1298 webContext()->bufferSubData(target, static_cast<GLintptr>(offset), size, data);
1299 }
1300
bufferSubData(GLenum target,long long offset,ArrayBuffer * data)1301 void WebGLRenderingContextBase::bufferSubData(GLenum target, long long offset, ArrayBuffer* data)
1302 {
1303 if (isContextLost())
1304 return;
1305 if (!data)
1306 return;
1307 bufferSubDataImpl(target, offset, data->byteLength(), data->data());
1308 }
1309
bufferSubData(GLenum target,long long offset,ArrayBufferView * data)1310 void WebGLRenderingContextBase::bufferSubData(GLenum target, long long offset, ArrayBufferView* data)
1311 {
1312 if (isContextLost())
1313 return;
1314 if (!data)
1315 return;
1316 bufferSubDataImpl(target, offset, data->byteLength(), data->baseAddress());
1317 }
1318
checkFramebufferStatus(GLenum target)1319 GLenum WebGLRenderingContextBase::checkFramebufferStatus(GLenum target)
1320 {
1321 if (isContextLost())
1322 return GL_FRAMEBUFFER_UNSUPPORTED;
1323 if (target != GL_FRAMEBUFFER) {
1324 synthesizeGLError(GL_INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1325 return 0;
1326 }
1327 if (!m_framebufferBinding || !m_framebufferBinding->object())
1328 return GL_FRAMEBUFFER_COMPLETE;
1329 const char* reason = "framebuffer incomplete";
1330 GLenum result = m_framebufferBinding->checkStatus(&reason);
1331 if (result != GL_FRAMEBUFFER_COMPLETE) {
1332 emitGLWarning("checkFramebufferStatus", reason);
1333 return result;
1334 }
1335 result = webContext()->checkFramebufferStatus(target);
1336 return result;
1337 }
1338
clear(GLbitfield mask)1339 void WebGLRenderingContextBase::clear(GLbitfield mask)
1340 {
1341 if (isContextLost())
1342 return;
1343 if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
1344 synthesizeGLError(GL_INVALID_VALUE, "clear", "invalid mask");
1345 return;
1346 }
1347 const char* reason = "framebuffer incomplete";
1348 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
1349 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
1350 return;
1351 }
1352 if (!clearIfComposited(mask))
1353 webContext()->clear(mask);
1354 markContextChanged(CanvasChanged);
1355 }
1356
clearColor(GLfloat r,GLfloat g,GLfloat b,GLfloat a)1357 void WebGLRenderingContextBase::clearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1358 {
1359 if (isContextLost())
1360 return;
1361 if (std::isnan(r))
1362 r = 0;
1363 if (std::isnan(g))
1364 g = 0;
1365 if (std::isnan(b))
1366 b = 0;
1367 if (std::isnan(a))
1368 a = 1;
1369 m_clearColor[0] = r;
1370 m_clearColor[1] = g;
1371 m_clearColor[2] = b;
1372 m_clearColor[3] = a;
1373 webContext()->clearColor(r, g, b, a);
1374 }
1375
clearDepth(GLfloat depth)1376 void WebGLRenderingContextBase::clearDepth(GLfloat depth)
1377 {
1378 if (isContextLost())
1379 return;
1380 m_clearDepth = depth;
1381 webContext()->clearDepth(depth);
1382 }
1383
clearStencil(GLint s)1384 void WebGLRenderingContextBase::clearStencil(GLint s)
1385 {
1386 if (isContextLost())
1387 return;
1388 m_clearStencil = s;
1389 webContext()->clearStencil(s);
1390 }
1391
colorMask(GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha)1392 void WebGLRenderingContextBase::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
1393 {
1394 if (isContextLost())
1395 return;
1396 m_colorMask[0] = red;
1397 m_colorMask[1] = green;
1398 m_colorMask[2] = blue;
1399 m_colorMask[3] = alpha;
1400 webContext()->colorMask(red, green, blue, alpha);
1401 }
1402
compileShader(WebGLShader * shader)1403 void WebGLRenderingContextBase::compileShader(WebGLShader* shader)
1404 {
1405 if (isContextLost() || !validateWebGLObject("compileShader", shader))
1406 return;
1407 webContext()->compileShader(objectOrZero(shader));
1408 }
1409
compressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,ArrayBufferView * data)1410 void WebGLRenderingContextBase::compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, ArrayBufferView* data)
1411 {
1412 if (isContextLost())
1413 return;
1414 if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1415 return;
1416
1417 if (!validateCompressedTexFormat(internalformat)) {
1418 synthesizeGLError(GL_INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1419 return;
1420 }
1421 if (border) {
1422 synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "border not 0");
1423 return;
1424 }
1425 if (!validateCompressedTexDimensions("compressedTexImage2D", NotTexSubImage2D, target, level, width, height, internalformat))
1426 return;
1427 if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1428 return;
1429
1430 WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1431 if (!tex)
1432 return;
1433 if (!isGLES2NPOTStrict()) {
1434 if (level && WebGLTexture::isNPOT(width, height)) {
1435 synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1436 return;
1437 }
1438 }
1439 webContext()->compressedTexImage2D(target, level, internalformat, width, height,
1440 border, data->byteLength(), data->baseAddress());
1441 tex->setLevelInfo(target, level, internalformat, width, height, GL_UNSIGNED_BYTE);
1442 }
1443
compressedTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,ArrayBufferView * data)1444 void WebGLRenderingContextBase::compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, ArrayBufferView* data)
1445 {
1446 if (isContextLost())
1447 return;
1448 if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1449 return;
1450 if (!validateCompressedTexFormat(format)) {
1451 synthesizeGLError(GL_INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1452 return;
1453 }
1454 if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1455 return;
1456
1457 WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1458 if (!tex)
1459 return;
1460
1461 if (format != tex->getInternalFormat(target, level)) {
1462 synthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1463 return;
1464 }
1465
1466 if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1467 return;
1468
1469 webContext()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1470 width, height, format, data->byteLength(), data->baseAddress());
1471 }
1472
validateSettableTexFormat(const char * functionName,GLenum format)1473 bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GLenum format)
1474 {
1475 if (WebGLImageConversion::getClearBitsByFormat(format) & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
1476 synthesizeGLError(GL_INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1477 return false;
1478 }
1479 return true;
1480 }
1481
copyTexImage2D(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,GLint border)1482 void WebGLRenderingContextBase::copyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
1483 {
1484 if (isContextLost())
1485 return;
1486 if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GL_UNSIGNED_BYTE))
1487 return;
1488 if (!validateSettableTexFormat("copyTexImage2D", internalformat))
1489 return;
1490 WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
1491 if (!tex)
1492 return;
1493 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, boundFramebufferColorFormat())) {
1494 synthesizeGLError(GL_INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
1495 return;
1496 }
1497 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1498 synthesizeGLError(GL_INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
1499 return;
1500 }
1501 const char* reason = "framebuffer incomplete";
1502 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
1503 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason);
1504 return;
1505 }
1506 clearIfComposited();
1507 ScopedDrawingBufferBinder binder(drawingBuffer(), m_framebufferBinding.get());
1508 webContext()->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1509 // FIXME: if the framebuffer is not complete, none of the below should be executed.
1510 tex->setLevelInfo(target, level, internalformat, width, height, GL_UNSIGNED_BYTE);
1511 }
1512
copyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height)1513 void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
1514 {
1515 if (isContextLost())
1516 return;
1517 if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1518 return;
1519 WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1520 if (!tex)
1521 return;
1522 if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1523 return;
1524 // Before checking if it is in the range, check if overflow happens first.
1525 Checked<GLint, RecordOverflow> maxX = xoffset;
1526 maxX += width;
1527 Checked<GLint, RecordOverflow> maxY = yoffset;
1528 maxY += height;
1529 if (maxX.hasOverflowed() || maxY.hasOverflowed()) {
1530 synthesizeGLError(GL_INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
1531 return;
1532 }
1533 if (maxX.unsafeGet() > tex->getWidth(target, level) || maxY.unsafeGet() > tex->getHeight(target, level)) {
1534 synthesizeGLError(GL_INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1535 return;
1536 }
1537 GLenum internalformat = tex->getInternalFormat(target, level);
1538 if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
1539 return;
1540 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, boundFramebufferColorFormat())) {
1541 synthesizeGLError(GL_INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1542 return;
1543 }
1544 const char* reason = "framebuffer incomplete";
1545 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
1546 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1547 return;
1548 }
1549 clearIfComposited();
1550 ScopedDrawingBufferBinder binder(drawingBuffer(), m_framebufferBinding.get());
1551 webContext()->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1552 }
1553
createBuffer()1554 PassRefPtrWillBeRawPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer()
1555 {
1556 if (isContextLost())
1557 return nullptr;
1558 RefPtrWillBeRawPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1559 addSharedObject(o.get());
1560 return o.release();
1561 }
1562
createFramebuffer()1563 PassRefPtrWillBeRawPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer()
1564 {
1565 if (isContextLost())
1566 return nullptr;
1567 RefPtrWillBeRawPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1568 addContextObject(o.get());
1569 return o.release();
1570 }
1571
createTexture()1572 PassRefPtrWillBeRawPtr<WebGLTexture> WebGLRenderingContextBase::createTexture()
1573 {
1574 if (isContextLost())
1575 return nullptr;
1576 RefPtrWillBeRawPtr<WebGLTexture> o = WebGLTexture::create(this);
1577 addSharedObject(o.get());
1578 return o.release();
1579 }
1580
createProgram()1581 PassRefPtrWillBeRawPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
1582 {
1583 if (isContextLost())
1584 return nullptr;
1585 RefPtrWillBeRawPtr<WebGLProgram> o = WebGLProgram::create(this);
1586 addSharedObject(o.get());
1587 return o.release();
1588 }
1589
createRenderbuffer()1590 PassRefPtrWillBeRawPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer()
1591 {
1592 if (isContextLost())
1593 return nullptr;
1594 RefPtrWillBeRawPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1595 addSharedObject(o.get());
1596 return o.release();
1597 }
1598
ensureEmulatedStencilBuffer(GLenum target,WebGLRenderbuffer * renderbuffer)1599 WebGLRenderbuffer* WebGLRenderingContextBase::ensureEmulatedStencilBuffer(GLenum target, WebGLRenderbuffer* renderbuffer)
1600 {
1601 if (isContextLost())
1602 return 0;
1603 if (!renderbuffer->emulatedStencilBuffer()) {
1604 renderbuffer->setEmulatedStencilBuffer(createRenderbuffer());
1605 webContext()->bindRenderbuffer(target, objectOrZero(renderbuffer->emulatedStencilBuffer()));
1606 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get()));
1607 }
1608 return renderbuffer->emulatedStencilBuffer();
1609 }
1610
createShader(GLenum type)1611 PassRefPtrWillBeRawPtr<WebGLShader> WebGLRenderingContextBase::createShader(GLenum type)
1612 {
1613 if (isContextLost())
1614 return nullptr;
1615 if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) {
1616 synthesizeGLError(GL_INVALID_ENUM, "createShader", "invalid shader type");
1617 return nullptr;
1618 }
1619
1620 RefPtrWillBeRawPtr<WebGLShader> o = WebGLShader::create(this, type);
1621 addSharedObject(o.get());
1622 return o.release();
1623 }
1624
cullFace(GLenum mode)1625 void WebGLRenderingContextBase::cullFace(GLenum mode)
1626 {
1627 if (isContextLost())
1628 return;
1629 switch (mode) {
1630 case GL_FRONT_AND_BACK:
1631 case GL_FRONT:
1632 case GL_BACK:
1633 break;
1634 default:
1635 synthesizeGLError(GL_INVALID_ENUM, "cullFace", "invalid mode");
1636 return;
1637 }
1638 webContext()->cullFace(mode);
1639 }
1640
deleteObject(WebGLObject * object)1641 bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
1642 {
1643 if (isContextLost() || !object)
1644 return false;
1645 if (!object->validate(contextGroup(), this)) {
1646 synthesizeGLError(GL_INVALID_OPERATION, "delete", "object does not belong to this context");
1647 return false;
1648 }
1649 if (object->object()) {
1650 // We need to pass in context here because we want
1651 // things in this context unbound.
1652 object->deleteObject(webContext());
1653 }
1654 return true;
1655 }
1656
deleteBuffer(WebGLBuffer * buffer)1657 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
1658 {
1659 if (!deleteObject(buffer))
1660 return;
1661 if (m_boundArrayBuffer == buffer)
1662 m_boundArrayBuffer = nullptr;
1663
1664 m_boundVertexArrayObject->unbindBuffer(buffer);
1665 }
1666
deleteFramebuffer(WebGLFramebuffer * framebuffer)1667 void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1668 {
1669 if (!deleteObject(framebuffer))
1670 return;
1671 if (framebuffer == m_framebufferBinding) {
1672 m_framebufferBinding = nullptr;
1673 drawingBuffer()->setFramebufferBinding(0);
1674 // Have to call bindFramebuffer here to bind back to internal fbo.
1675 drawingBuffer()->bind();
1676 }
1677 }
1678
deleteProgram(WebGLProgram * program)1679 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
1680 {
1681 deleteObject(program);
1682 // We don't reset m_currentProgram to 0 here because the deletion of the
1683 // current program is delayed.
1684 }
1685
deleteRenderbuffer(WebGLRenderbuffer * renderbuffer)1686 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1687 {
1688 if (!deleteObject(renderbuffer))
1689 return;
1690 if (renderbuffer == m_renderbufferBinding)
1691 m_renderbufferBinding = nullptr;
1692 if (m_framebufferBinding)
1693 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1694 }
1695
deleteShader(WebGLShader * shader)1696 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
1697 {
1698 deleteObject(shader);
1699 }
1700
deleteTexture(WebGLTexture * texture)1701 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
1702 {
1703 if (!deleteObject(texture))
1704 return;
1705
1706 int maxBoundTextureIndex = -1;
1707 for (size_t i = 0; i < m_onePlusMaxNonDefaultTextureUnit; ++i) {
1708 if (texture == m_textureUnits[i].m_texture2DBinding) {
1709 m_textureUnits[i].m_texture2DBinding = nullptr;
1710 maxBoundTextureIndex = i;
1711 if (!i)
1712 drawingBuffer()->setTexture2DBinding(0);
1713 }
1714 if (texture == m_textureUnits[i].m_textureCubeMapBinding) {
1715 m_textureUnits[i].m_textureCubeMapBinding = nullptr;
1716 maxBoundTextureIndex = i;
1717 }
1718 }
1719 if (m_framebufferBinding)
1720 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1721
1722 // If the deleted was bound to the the current maximum index, trace backwards to find the new max texture index
1723 if (m_onePlusMaxNonDefaultTextureUnit == static_cast<unsigned long>(maxBoundTextureIndex + 1)) {
1724 findNewMaxNonDefaultTextureUnit();
1725 }
1726 }
1727
depthFunc(GLenum func)1728 void WebGLRenderingContextBase::depthFunc(GLenum func)
1729 {
1730 if (isContextLost())
1731 return;
1732 if (!validateStencilOrDepthFunc("depthFunc", func))
1733 return;
1734 webContext()->depthFunc(func);
1735 }
1736
depthMask(GLboolean flag)1737 void WebGLRenderingContextBase::depthMask(GLboolean flag)
1738 {
1739 if (isContextLost())
1740 return;
1741 m_depthMask = flag;
1742 webContext()->depthMask(flag);
1743 }
1744
depthRange(GLfloat zNear,GLfloat zFar)1745 void WebGLRenderingContextBase::depthRange(GLfloat zNear, GLfloat zFar)
1746 {
1747 if (isContextLost())
1748 return;
1749 if (zNear > zFar) {
1750 synthesizeGLError(GL_INVALID_OPERATION, "depthRange", "zNear > zFar");
1751 return;
1752 }
1753 webContext()->depthRange(zNear, zFar);
1754 }
1755
detachShader(WebGLProgram * program,WebGLShader * shader)1756 void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader)
1757 {
1758 if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1759 return;
1760 if (!program->detachShader(shader)) {
1761 synthesizeGLError(GL_INVALID_OPERATION, "detachShader", "shader not attached");
1762 return;
1763 }
1764 webContext()->detachShader(objectOrZero(program), objectOrZero(shader));
1765 shader->onDetached(webContext());
1766 }
1767
disable(GLenum cap)1768 void WebGLRenderingContextBase::disable(GLenum cap)
1769 {
1770 if (isContextLost() || !validateCapability("disable", cap))
1771 return;
1772 if (cap == GL_STENCIL_TEST) {
1773 m_stencilEnabled = false;
1774 applyStencilTest();
1775 return;
1776 }
1777 if (cap == GL_SCISSOR_TEST) {
1778 m_scissorEnabled = false;
1779 drawingBuffer()->setScissorEnabled(m_scissorEnabled);
1780 }
1781 webContext()->disable(cap);
1782 }
1783
disableVertexAttribArray(GLuint index)1784 void WebGLRenderingContextBase::disableVertexAttribArray(GLuint index)
1785 {
1786 if (isContextLost())
1787 return;
1788 if (index >= m_maxVertexAttribs) {
1789 synthesizeGLError(GL_INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1790 return;
1791 }
1792
1793 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1794 state.enabled = false;
1795
1796 webContext()->disableVertexAttribArray(index);
1797 }
1798
validateRenderingState(const char * functionName)1799 bool WebGLRenderingContextBase::validateRenderingState(const char* functionName)
1800 {
1801 if (!m_currentProgram) {
1802 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no valid shader program in use");
1803 return false;
1804 }
1805
1806 return true;
1807 }
1808
validateWebGLObject(const char * functionName,WebGLObject * object)1809 bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
1810 {
1811 if (!object || !object->object()) {
1812 synthesizeGLError(GL_INVALID_VALUE, functionName, "no object or object deleted");
1813 return false;
1814 }
1815 if (!object->validate(contextGroup(), this)) {
1816 synthesizeGLError(GL_INVALID_OPERATION, functionName, "object does not belong to this context");
1817 return false;
1818 }
1819 return true;
1820 }
1821
drawArrays(GLenum mode,GLint first,GLsizei count)1822 void WebGLRenderingContextBase::drawArrays(GLenum mode, GLint first, GLsizei count)
1823 {
1824 if (!validateDrawArrays("drawArrays", mode, first, count))
1825 return;
1826
1827 clearIfComposited();
1828
1829 handleTextureCompleteness("drawArrays", true);
1830 webContext()->drawArrays(mode, first, count);
1831 handleTextureCompleteness("drawArrays", false);
1832 markContextChanged(CanvasChanged);
1833 }
1834
drawElements(GLenum mode,GLsizei count,GLenum type,long long offset)1835 void WebGLRenderingContextBase::drawElements(GLenum mode, GLsizei count, GLenum type, long long offset)
1836 {
1837 if (!validateDrawElements("drawElements", mode, count, type, offset))
1838 return;
1839
1840 clearIfComposited();
1841
1842 handleTextureCompleteness("drawElements", true);
1843 webContext()->drawElements(mode, count, type, static_cast<GLintptr>(offset));
1844 handleTextureCompleteness("drawElements", false);
1845 markContextChanged(CanvasChanged);
1846 }
1847
drawArraysInstancedANGLE(GLenum mode,GLint first,GLsizei count,GLsizei primcount)1848 void WebGLRenderingContextBase::drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1849 {
1850 if (!validateDrawArrays("drawArraysInstancedANGLE", mode, first, count))
1851 return;
1852
1853 if (!validateDrawInstanced("drawArraysInstancedANGLE", primcount))
1854 return;
1855
1856 clearIfComposited();
1857
1858 handleTextureCompleteness("drawArraysInstancedANGLE", true);
1859 webContext()->drawArraysInstancedANGLE(mode, first, count, primcount);
1860 handleTextureCompleteness("drawArraysInstancedANGLE", false);
1861 markContextChanged(CanvasChanged);
1862 }
1863
drawElementsInstancedANGLE(GLenum mode,GLsizei count,GLenum type,long long offset,GLsizei primcount)1864 void WebGLRenderingContextBase::drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, long long offset, GLsizei primcount)
1865 {
1866 if (!validateDrawElements("drawElementsInstancedANGLE", mode, count, type, offset))
1867 return;
1868
1869 if (!validateDrawInstanced("drawElementsInstancedANGLE", primcount))
1870 return;
1871
1872 clearIfComposited();
1873
1874 handleTextureCompleteness("drawElementsInstancedANGLE", true);
1875 webContext()->drawElementsInstancedANGLE(mode, count, type, static_cast<GLintptr>(offset), primcount);
1876 handleTextureCompleteness("drawElementsInstancedANGLE", false);
1877 markContextChanged(CanvasChanged);
1878 }
1879
enable(GLenum cap)1880 void WebGLRenderingContextBase::enable(GLenum cap)
1881 {
1882 if (isContextLost() || !validateCapability("enable", cap))
1883 return;
1884 if (cap == GL_STENCIL_TEST) {
1885 m_stencilEnabled = true;
1886 applyStencilTest();
1887 return;
1888 }
1889 if (cap == GL_SCISSOR_TEST) {
1890 m_scissorEnabled = true;
1891 drawingBuffer()->setScissorEnabled(m_scissorEnabled);
1892 }
1893 webContext()->enable(cap);
1894 }
1895
enableVertexAttribArray(GLuint index)1896 void WebGLRenderingContextBase::enableVertexAttribArray(GLuint index)
1897 {
1898 if (isContextLost())
1899 return;
1900 if (index >= m_maxVertexAttribs) {
1901 synthesizeGLError(GL_INVALID_VALUE, "enableVertexAttribArray", "index out of range");
1902 return;
1903 }
1904
1905 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1906 state.enabled = true;
1907
1908 webContext()->enableVertexAttribArray(index);
1909 }
1910
finish()1911 void WebGLRenderingContextBase::finish()
1912 {
1913 if (isContextLost())
1914 return;
1915 webContext()->flush(); // Intentionally a flush, not a finish.
1916 }
1917
flush()1918 void WebGLRenderingContextBase::flush()
1919 {
1920 if (isContextLost())
1921 return;
1922 webContext()->flush();
1923 }
1924
framebufferRenderbuffer(GLenum target,GLenum attachment,GLenum renderbuffertarget,WebGLRenderbuffer * buffer)1925 void WebGLRenderingContextBase::framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer* buffer)
1926 {
1927 if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
1928 return;
1929 if (renderbuffertarget != GL_RENDERBUFFER) {
1930 synthesizeGLError(GL_INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
1931 return;
1932 }
1933 if (buffer && !buffer->validate(contextGroup(), this)) {
1934 synthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
1935 return;
1936 }
1937 // Don't allow the default framebuffer to be mutated; all current
1938 // implementations use an FBO internally in place of the default
1939 // FBO.
1940 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1941 synthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
1942 return;
1943 }
1944 Platform3DObject bufferObject = objectOrZero(buffer);
1945 switch (attachment) {
1946 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
1947 if (isDepthStencilSupported() || !buffer) {
1948 webContext()->framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1949 webContext()->framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1950 } else {
1951 WebGLRenderbuffer* emulatedStencilBuffer = ensureEmulatedStencilBuffer(renderbuffertarget, buffer);
1952 if (!emulatedStencilBuffer) {
1953 synthesizeGLError(GL_OUT_OF_MEMORY, "framebufferRenderbuffer", "out of memory");
1954 return;
1955 }
1956 webContext()->framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1957 webContext()->framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, objectOrZero(emulatedStencilBuffer));
1958 }
1959 break;
1960 default:
1961 webContext()->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
1962 }
1963 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
1964 applyStencilTest();
1965 }
1966
framebufferTexture2D(GLenum target,GLenum attachment,GLenum textarget,WebGLTexture * texture,GLint level)1967 void WebGLRenderingContextBase::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, WebGLTexture* texture, GLint level)
1968 {
1969 if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
1970 return;
1971 if (level) {
1972 synthesizeGLError(GL_INVALID_VALUE, "framebufferTexture2D", "level not 0");
1973 return;
1974 }
1975 if (texture && !texture->validate(contextGroup(), this)) {
1976 synthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
1977 return;
1978 }
1979 // Don't allow the default framebuffer to be mutated; all current
1980 // implementations use an FBO internally in place of the default
1981 // FBO.
1982 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1983 synthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
1984 return;
1985 }
1986 Platform3DObject textureObject = objectOrZero(texture);
1987 switch (attachment) {
1988 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
1989 webContext()->framebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textarget, textureObject, level);
1990 webContext()->framebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textarget, textureObject, level);
1991 break;
1992 case GL_DEPTH_ATTACHMENT:
1993 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level);
1994 break;
1995 case GL_STENCIL_ATTACHMENT:
1996 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level);
1997 break;
1998 default:
1999 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2000 }
2001 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2002 applyStencilTest();
2003 }
2004
frontFace(GLenum mode)2005 void WebGLRenderingContextBase::frontFace(GLenum mode)
2006 {
2007 if (isContextLost())
2008 return;
2009 switch (mode) {
2010 case GL_CW:
2011 case GL_CCW:
2012 break;
2013 default:
2014 synthesizeGLError(GL_INVALID_ENUM, "frontFace", "invalid mode");
2015 return;
2016 }
2017 webContext()->frontFace(mode);
2018 }
2019
generateMipmap(GLenum target)2020 void WebGLRenderingContextBase::generateMipmap(GLenum target)
2021 {
2022 if (isContextLost())
2023 return;
2024 WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2025 if (!tex)
2026 return;
2027 if (!tex->canGenerateMipmaps()) {
2028 synthesizeGLError(GL_INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2029 return;
2030 }
2031 if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2032 return;
2033
2034 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2035 // on Mac. Remove the hack once this driver bug is fixed.
2036 #if OS(MACOSX)
2037 bool needToResetMinFilter = false;
2038 if (tex->getMinFilter() != GL_NEAREST_MIPMAP_LINEAR) {
2039 webContext()->texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
2040 needToResetMinFilter = true;
2041 }
2042 #endif
2043 webContext()->generateMipmap(target);
2044 #if OS(MACOSX)
2045 if (needToResetMinFilter)
2046 webContext()->texParameteri(target, GL_TEXTURE_MIN_FILTER, tex->getMinFilter());
2047 #endif
2048 tex->generateMipmapLevelInfo();
2049 }
2050
getActiveAttrib(WebGLProgram * program,GLuint index)2051 PassRefPtrWillBeRawPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GLuint index)
2052 {
2053 if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
2054 return nullptr;
2055 blink::WebGraphicsContext3D::ActiveInfo info;
2056 if (!webContext()->getActiveAttrib(objectOrZero(program), index, info))
2057 return nullptr;
2058 return WebGLActiveInfo::create(info.name, info.type, info.size);
2059 }
2060
getActiveUniform(WebGLProgram * program,GLuint index)2061 PassRefPtrWillBeRawPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GLuint index)
2062 {
2063 if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
2064 return nullptr;
2065 blink::WebGraphicsContext3D::ActiveInfo info;
2066 if (!webContext()->getActiveUniform(objectOrZero(program), index, info))
2067 return nullptr;
2068 return WebGLActiveInfo::create(info.name, info.type, info.size);
2069 }
2070
getAttachedShaders(WebGLProgram * program)2071 Nullable<WillBeHeapVector<RefPtrWillBeMember<WebGLShader> > > WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program)
2072 {
2073 if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
2074 return Nullable<WillBeHeapVector<RefPtrWillBeMember<WebGLShader> > >();
2075
2076 WillBeHeapVector<RefPtrWillBeMember<WebGLShader> > shaderObjects;
2077 const GLenum shaderType[] = {
2078 GL_VERTEX_SHADER,
2079 GL_FRAGMENT_SHADER
2080 };
2081 for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GLenum); ++i) {
2082 WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2083 if (shader)
2084 shaderObjects.append(shader);
2085 }
2086 return shaderObjects;
2087 }
2088
getAttribLocation(WebGLProgram * program,const String & name)2089 GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name)
2090 {
2091 if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
2092 return -1;
2093 if (!validateLocationLength("getAttribLocation", name))
2094 return -1;
2095 if (!validateString("getAttribLocation", name))
2096 return -1;
2097 if (isPrefixReserved(name))
2098 return -1;
2099 if (!program->linkStatus()) {
2100 synthesizeGLError(GL_INVALID_OPERATION, "getAttribLocation", "program not linked");
2101 return 0;
2102 }
2103 return webContext()->getAttribLocation(objectOrZero(program), name.utf8().data());
2104 }
2105
getBufferParameter(GLenum target,GLenum pname)2106 WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GLenum target, GLenum pname)
2107 {
2108 if (isContextLost())
2109 return WebGLGetInfo();
2110 if (target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER) {
2111 synthesizeGLError(GL_INVALID_ENUM, "getBufferParameter", "invalid target");
2112 return WebGLGetInfo();
2113 }
2114
2115 if (pname != GL_BUFFER_SIZE && pname != GL_BUFFER_USAGE) {
2116 synthesizeGLError(GL_INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2117 return WebGLGetInfo();
2118 }
2119
2120 GLint value = 0;
2121 webContext()->getBufferParameteriv(target, pname, &value);
2122 if (pname == GL_BUFFER_SIZE)
2123 return WebGLGetInfo(value);
2124 return WebGLGetInfo(static_cast<unsigned>(value));
2125 }
2126
getContextAttributes()2127 PassRefPtrWillBeRawPtr<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes()
2128 {
2129 if (isContextLost())
2130 return nullptr;
2131 // We always need to return a new WebGLContextAttributes object to
2132 // prevent the user from mutating any cached version.
2133 blink::WebGraphicsContext3D::Attributes attrs = drawingBuffer()->getActualAttributes();
2134 RefPtrWillBeRawPtr<WebGLContextAttributes> attributes = m_requestedAttributes->clone();
2135 // Some requested attributes may not be honored, so we need to query the underlying
2136 // context/drawing buffer and adjust accordingly.
2137 if (m_requestedAttributes->depth() && !attrs.depth)
2138 attributes->setDepth(false);
2139 if (m_requestedAttributes->stencil() && !attrs.stencil)
2140 attributes->setStencil(false);
2141 attributes->setAntialias(drawingBuffer()->multisample());
2142 return attributes.release();
2143 }
2144
getError()2145 GLenum WebGLRenderingContextBase::getError()
2146 {
2147 if (m_lostContextErrors.size()) {
2148 GLenum err = m_lostContextErrors.first();
2149 m_lostContextErrors.remove(0);
2150 return err;
2151 }
2152
2153 if (isContextLost())
2154 return GL_NO_ERROR;
2155
2156 return webContext()->getError();
2157 }
2158
prefixes() const2159 const char* const* WebGLRenderingContextBase::ExtensionTracker::prefixes() const
2160 {
2161 static const char* const unprefixed[] = { "", 0, };
2162 return m_prefixes ? m_prefixes : unprefixed;
2163 }
2164
matchesNameWithPrefixes(const String & name) const2165 bool WebGLRenderingContextBase::ExtensionTracker::matchesNameWithPrefixes(const String& name) const
2166 {
2167 const char* const* prefixSet = prefixes();
2168 for (; *prefixSet; ++prefixSet) {
2169 String prefixedName = String(*prefixSet) + extensionName();
2170 if (equalIgnoringCase(prefixedName, name)) {
2171 return true;
2172 }
2173 }
2174 return false;
2175 }
2176
extensionSupportedAndAllowed(const ExtensionTracker * tracker)2177 bool WebGLRenderingContextBase::extensionSupportedAndAllowed(const ExtensionTracker* tracker)
2178 {
2179 if (tracker->draft() && !RuntimeEnabledFeatures::webGLDraftExtensionsEnabled())
2180 return false;
2181 if (!tracker->supported(this))
2182 return false;
2183 return true;
2184 }
2185
2186
getExtension(const String & name)2187 PassRefPtrWillBeRawPtr<WebGLExtension> WebGLRenderingContextBase::getExtension(const String& name)
2188 {
2189 if (isContextLost())
2190 return nullptr;
2191
2192 for (size_t i = 0; i < m_extensions.size(); ++i) {
2193 ExtensionTracker* tracker = m_extensions[i].get();
2194 if (tracker->matchesNameWithPrefixes(name)) {
2195 if (!extensionSupportedAndAllowed(tracker))
2196 return nullptr;
2197
2198 RefPtrWillBeRawPtr<WebGLExtension> extension = tracker->getExtension(this);
2199 if (extension)
2200 m_extensionEnabled[extension->name()] = true;
2201 return extension.release();
2202 }
2203 }
2204
2205 return nullptr;
2206 }
2207
getFramebufferAttachmentParameter(GLenum target,GLenum attachment,GLenum pname)2208 WebGLGetInfo WebGLRenderingContextBase::getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname)
2209 {
2210 if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2211 return WebGLGetInfo();
2212
2213 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2214 synthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2215 return WebGLGetInfo();
2216 }
2217
2218 WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
2219 if (!object) {
2220 if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2221 return WebGLGetInfo(GL_NONE);
2222 // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2223 // specifies INVALID_OPERATION.
2224 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2225 return WebGLGetInfo();
2226 }
2227
2228 ASSERT(object->isTexture() || object->isRenderbuffer());
2229 if (object->isTexture()) {
2230 switch (pname) {
2231 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2232 return WebGLGetInfo(GL_TEXTURE);
2233 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2234 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLTexture>(static_cast<WebGLTexture*>(object)));
2235 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2236 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2237 {
2238 GLint value = 0;
2239 webContext()->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2240 return WebGLGetInfo(value);
2241 }
2242 default:
2243 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2244 return WebGLGetInfo();
2245 }
2246 } else {
2247 switch (pname) {
2248 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2249 return WebGLGetInfo(GL_RENDERBUFFER);
2250 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2251 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLRenderbuffer>(static_cast<WebGLRenderbuffer*>(object)));
2252 default:
2253 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2254 return WebGLGetInfo();
2255 }
2256 }
2257 }
2258
getParameter(GLenum pname)2259 WebGLGetInfo WebGLRenderingContextBase::getParameter(GLenum pname)
2260 {
2261 if (isContextLost())
2262 return WebGLGetInfo();
2263 const int intZero = 0;
2264 switch (pname) {
2265 case GL_ACTIVE_TEXTURE:
2266 return getUnsignedIntParameter(pname);
2267 case GL_ALIASED_LINE_WIDTH_RANGE:
2268 return getWebGLFloatArrayParameter(pname);
2269 case GL_ALIASED_POINT_SIZE_RANGE:
2270 return getWebGLFloatArrayParameter(pname);
2271 case GL_ALPHA_BITS:
2272 return getIntParameter(pname);
2273 case GL_ARRAY_BUFFER_BINDING:
2274 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLBuffer>(m_boundArrayBuffer.get()));
2275 case GL_BLEND:
2276 return getBooleanParameter(pname);
2277 case GL_BLEND_COLOR:
2278 return getWebGLFloatArrayParameter(pname);
2279 case GL_BLEND_DST_ALPHA:
2280 return getUnsignedIntParameter(pname);
2281 case GL_BLEND_DST_RGB:
2282 return getUnsignedIntParameter(pname);
2283 case GL_BLEND_EQUATION_ALPHA:
2284 return getUnsignedIntParameter(pname);
2285 case GL_BLEND_EQUATION_RGB:
2286 return getUnsignedIntParameter(pname);
2287 case GL_BLEND_SRC_ALPHA:
2288 return getUnsignedIntParameter(pname);
2289 case GL_BLEND_SRC_RGB:
2290 return getUnsignedIntParameter(pname);
2291 case GL_BLUE_BITS:
2292 return getIntParameter(pname);
2293 case GL_COLOR_CLEAR_VALUE:
2294 return getWebGLFloatArrayParameter(pname);
2295 case GL_COLOR_WRITEMASK:
2296 return getBooleanArrayParameter(pname);
2297 case GL_COMPRESSED_TEXTURE_FORMATS:
2298 return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2299 case GL_CULL_FACE:
2300 return getBooleanParameter(pname);
2301 case GL_CULL_FACE_MODE:
2302 return getUnsignedIntParameter(pname);
2303 case GL_CURRENT_PROGRAM:
2304 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLProgram>(m_currentProgram.get()));
2305 case GL_DEPTH_BITS:
2306 if (!m_framebufferBinding && !m_requestedAttributes->depth())
2307 return WebGLGetInfo(intZero);
2308 return getIntParameter(pname);
2309 case GL_DEPTH_CLEAR_VALUE:
2310 return getFloatParameter(pname);
2311 case GL_DEPTH_FUNC:
2312 return getUnsignedIntParameter(pname);
2313 case GL_DEPTH_RANGE:
2314 return getWebGLFloatArrayParameter(pname);
2315 case GL_DEPTH_TEST:
2316 return getBooleanParameter(pname);
2317 case GL_DEPTH_WRITEMASK:
2318 return getBooleanParameter(pname);
2319 case GL_DITHER:
2320 return getBooleanParameter(pname);
2321 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
2322 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLBuffer>(m_boundVertexArrayObject->boundElementArrayBuffer()));
2323 case GL_FRAMEBUFFER_BINDING:
2324 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLFramebuffer>(m_framebufferBinding.get()));
2325 case GL_FRONT_FACE:
2326 return getUnsignedIntParameter(pname);
2327 case GL_GENERATE_MIPMAP_HINT:
2328 return getUnsignedIntParameter(pname);
2329 case GL_GREEN_BITS:
2330 return getIntParameter(pname);
2331 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
2332 return getIntParameter(pname);
2333 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2334 return getIntParameter(pname);
2335 case GL_LINE_WIDTH:
2336 return getFloatParameter(pname);
2337 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2338 return getIntParameter(pname);
2339 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
2340 return getIntParameter(pname);
2341 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
2342 return getIntParameter(pname);
2343 case GL_MAX_RENDERBUFFER_SIZE:
2344 return getIntParameter(pname);
2345 case GL_MAX_TEXTURE_IMAGE_UNITS:
2346 return getIntParameter(pname);
2347 case GL_MAX_TEXTURE_SIZE:
2348 return getIntParameter(pname);
2349 case GL_MAX_VARYING_VECTORS:
2350 return getIntParameter(pname);
2351 case GL_MAX_VERTEX_ATTRIBS:
2352 return getIntParameter(pname);
2353 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2354 return getIntParameter(pname);
2355 case GL_MAX_VERTEX_UNIFORM_VECTORS:
2356 return getIntParameter(pname);
2357 case GL_MAX_VIEWPORT_DIMS:
2358 return getWebGLIntArrayParameter(pname);
2359 case GL_NUM_SHADER_BINARY_FORMATS:
2360 // FIXME: should we always return 0 for this?
2361 return getIntParameter(pname);
2362 case GL_PACK_ALIGNMENT:
2363 return getIntParameter(pname);
2364 case GL_POLYGON_OFFSET_FACTOR:
2365 return getFloatParameter(pname);
2366 case GL_POLYGON_OFFSET_FILL:
2367 return getBooleanParameter(pname);
2368 case GL_POLYGON_OFFSET_UNITS:
2369 return getFloatParameter(pname);
2370 case GL_RED_BITS:
2371 return getIntParameter(pname);
2372 case GL_RENDERBUFFER_BINDING:
2373 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLRenderbuffer>(m_renderbufferBinding.get()));
2374 case GL_RENDERER:
2375 return WebGLGetInfo(String("WebKit WebGL"));
2376 case GL_SAMPLE_BUFFERS:
2377 return getIntParameter(pname);
2378 case GL_SAMPLE_COVERAGE_INVERT:
2379 return getBooleanParameter(pname);
2380 case GL_SAMPLE_COVERAGE_VALUE:
2381 return getFloatParameter(pname);
2382 case GL_SAMPLES:
2383 return getIntParameter(pname);
2384 case GL_SCISSOR_BOX:
2385 return getWebGLIntArrayParameter(pname);
2386 case GL_SCISSOR_TEST:
2387 return getBooleanParameter(pname);
2388 case GL_SHADING_LANGUAGE_VERSION:
2389 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + String(webContext()->getString(GL_SHADING_LANGUAGE_VERSION)) + ")");
2390 case GL_STENCIL_BACK_FAIL:
2391 return getUnsignedIntParameter(pname);
2392 case GL_STENCIL_BACK_FUNC:
2393 return getUnsignedIntParameter(pname);
2394 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
2395 return getUnsignedIntParameter(pname);
2396 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
2397 return getUnsignedIntParameter(pname);
2398 case GL_STENCIL_BACK_REF:
2399 return getIntParameter(pname);
2400 case GL_STENCIL_BACK_VALUE_MASK:
2401 return getUnsignedIntParameter(pname);
2402 case GL_STENCIL_BACK_WRITEMASK:
2403 return getUnsignedIntParameter(pname);
2404 case GL_STENCIL_BITS:
2405 if (!m_framebufferBinding && !m_requestedAttributes->stencil())
2406 return WebGLGetInfo(intZero);
2407 return getIntParameter(pname);
2408 case GL_STENCIL_CLEAR_VALUE:
2409 return getIntParameter(pname);
2410 case GL_STENCIL_FAIL:
2411 return getUnsignedIntParameter(pname);
2412 case GL_STENCIL_FUNC:
2413 return getUnsignedIntParameter(pname);
2414 case GL_STENCIL_PASS_DEPTH_FAIL:
2415 return getUnsignedIntParameter(pname);
2416 case GL_STENCIL_PASS_DEPTH_PASS:
2417 return getUnsignedIntParameter(pname);
2418 case GL_STENCIL_REF:
2419 return getIntParameter(pname);
2420 case GL_STENCIL_TEST:
2421 return getBooleanParameter(pname);
2422 case GL_STENCIL_VALUE_MASK:
2423 return getUnsignedIntParameter(pname);
2424 case GL_STENCIL_WRITEMASK:
2425 return getUnsignedIntParameter(pname);
2426 case GL_SUBPIXEL_BITS:
2427 return getIntParameter(pname);
2428 case GL_TEXTURE_BINDING_2D:
2429 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
2430 case GL_TEXTURE_BINDING_CUBE_MAP:
2431 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get()));
2432 case GL_UNPACK_ALIGNMENT:
2433 return getIntParameter(pname);
2434 case GC3D_UNPACK_FLIP_Y_WEBGL:
2435 return WebGLGetInfo(m_unpackFlipY);
2436 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2437 return WebGLGetInfo(m_unpackPremultiplyAlpha);
2438 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
2439 return WebGLGetInfo(m_unpackColorspaceConversion);
2440 case GL_VENDOR:
2441 return WebGLGetInfo(String("WebKit"));
2442 case GL_VERSION:
2443 return WebGLGetInfo("WebGL 1.0 (" + String(webContext()->getString(GL_VERSION)) + ")");
2444 case GL_VIEWPORT:
2445 return getWebGLIntArrayParameter(pname);
2446 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2447 if (extensionEnabled(OESStandardDerivativesName))
2448 return getUnsignedIntParameter(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2449 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2450 return WebGLGetInfo();
2451 case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2452 if (extensionEnabled(WebGLDebugRendererInfoName))
2453 return WebGLGetInfo(webContext()->getString(GL_RENDERER));
2454 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2455 return WebGLGetInfo();
2456 case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2457 if (extensionEnabled(WebGLDebugRendererInfoName))
2458 return WebGLGetInfo(webContext()->getString(GL_VENDOR));
2459 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2460 return WebGLGetInfo();
2461 case GL_VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2462 if (extensionEnabled(OESVertexArrayObjectName)) {
2463 if (!m_boundVertexArrayObject->isDefaultObject())
2464 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject.get()));
2465 return WebGLGetInfo();
2466 }
2467 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2468 return WebGLGetInfo();
2469 case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2470 if (extensionEnabled(EXTTextureFilterAnisotropicName))
2471 return getUnsignedIntParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2472 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2473 return WebGLGetInfo();
2474 case GL_MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
2475 if (extensionEnabled(WebGLDrawBuffersName))
2476 return WebGLGetInfo(maxColorAttachments());
2477 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
2478 return WebGLGetInfo();
2479 case GL_MAX_DRAW_BUFFERS_EXT:
2480 if (extensionEnabled(WebGLDrawBuffersName))
2481 return WebGLGetInfo(maxDrawBuffers());
2482 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
2483 return WebGLGetInfo();
2484 default:
2485 if (extensionEnabled(WebGLDrawBuffersName)
2486 && pname >= GL_DRAW_BUFFER0_EXT
2487 && pname < static_cast<GLenum>(GL_DRAW_BUFFER0_EXT + maxDrawBuffers())) {
2488 GLint value = GL_NONE;
2489 if (m_framebufferBinding)
2490 value = m_framebufferBinding->getDrawBuffer(pname);
2491 else // emulated backbuffer
2492 value = m_backDrawBuffer;
2493 return WebGLGetInfo(value);
2494 }
2495 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name");
2496 return WebGLGetInfo();
2497 }
2498 }
2499
getProgramParameter(WebGLProgram * program,GLenum pname)2500 WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GLenum pname)
2501 {
2502 if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
2503 return WebGLGetInfo();
2504
2505 GLint value = 0;
2506 switch (pname) {
2507 case GL_DELETE_STATUS:
2508 return WebGLGetInfo(program->isDeleted());
2509 case GL_VALIDATE_STATUS:
2510 webContext()->getProgramiv(objectOrZero(program), pname, &value);
2511 return WebGLGetInfo(static_cast<bool>(value));
2512 case GL_LINK_STATUS:
2513 return WebGLGetInfo(program->linkStatus());
2514 case GL_ATTACHED_SHADERS:
2515 case GL_ACTIVE_ATTRIBUTES:
2516 case GL_ACTIVE_UNIFORMS:
2517 webContext()->getProgramiv(objectOrZero(program), pname, &value);
2518 return WebGLGetInfo(value);
2519 default:
2520 synthesizeGLError(GL_INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2521 return WebGLGetInfo();
2522 }
2523 }
2524
getProgramInfoLog(WebGLProgram * program)2525 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program)
2526 {
2527 if (isContextLost())
2528 return String();
2529 if (!validateWebGLObject("getProgramInfoLog", program))
2530 return "";
2531 return ensureNotNull(webContext()->getProgramInfoLog(objectOrZero(program)));
2532 }
2533
getRenderbufferParameter(GLenum target,GLenum pname)2534 WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GLenum target, GLenum pname)
2535 {
2536 if (isContextLost())
2537 return WebGLGetInfo();
2538 if (target != GL_RENDERBUFFER) {
2539 synthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2540 return WebGLGetInfo();
2541 }
2542 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2543 synthesizeGLError(GL_INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2544 return WebGLGetInfo();
2545 }
2546
2547 GLint value = 0;
2548 switch (pname) {
2549 case GL_RENDERBUFFER_WIDTH:
2550 case GL_RENDERBUFFER_HEIGHT:
2551 case GL_RENDERBUFFER_RED_SIZE:
2552 case GL_RENDERBUFFER_GREEN_SIZE:
2553 case GL_RENDERBUFFER_BLUE_SIZE:
2554 case GL_RENDERBUFFER_ALPHA_SIZE:
2555 case GL_RENDERBUFFER_DEPTH_SIZE:
2556 webContext()->getRenderbufferParameteriv(target, pname, &value);
2557 return WebGLGetInfo(value);
2558 case GL_RENDERBUFFER_STENCIL_SIZE:
2559 if (m_renderbufferBinding->emulatedStencilBuffer()) {
2560 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding->emulatedStencilBuffer()));
2561 webContext()->getRenderbufferParameteriv(target, pname, &value);
2562 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get()));
2563 } else {
2564 webContext()->getRenderbufferParameteriv(target, pname, &value);
2565 }
2566 return WebGLGetInfo(value);
2567 case GL_RENDERBUFFER_INTERNAL_FORMAT:
2568 return WebGLGetInfo(m_renderbufferBinding->internalFormat());
2569 default:
2570 synthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2571 return WebGLGetInfo();
2572 }
2573 }
2574
getShaderParameter(WebGLShader * shader,GLenum pname)2575 WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GLenum pname)
2576 {
2577 if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
2578 return WebGLGetInfo();
2579 GLint value = 0;
2580 switch (pname) {
2581 case GL_DELETE_STATUS:
2582 return WebGLGetInfo(shader->isDeleted());
2583 case GL_COMPILE_STATUS:
2584 webContext()->getShaderiv(objectOrZero(shader), pname, &value);
2585 return WebGLGetInfo(static_cast<bool>(value));
2586 case GL_SHADER_TYPE:
2587 webContext()->getShaderiv(objectOrZero(shader), pname, &value);
2588 return WebGLGetInfo(static_cast<unsigned>(value));
2589 default:
2590 synthesizeGLError(GL_INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2591 return WebGLGetInfo();
2592 }
2593 }
2594
getShaderInfoLog(WebGLShader * shader)2595 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader)
2596 {
2597 if (isContextLost())
2598 return String();
2599 if (!validateWebGLObject("getShaderInfoLog", shader))
2600 return "";
2601 return ensureNotNull(webContext()->getShaderInfoLog(objectOrZero(shader)));
2602 }
2603
getShaderPrecisionFormat(GLenum shaderType,GLenum precisionType)2604 PassRefPtrWillBeRawPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GLenum shaderType, GLenum precisionType)
2605 {
2606 if (isContextLost())
2607 return nullptr;
2608 switch (shaderType) {
2609 case GL_VERTEX_SHADER:
2610 case GL_FRAGMENT_SHADER:
2611 break;
2612 default:
2613 synthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2614 return nullptr;
2615 }
2616 switch (precisionType) {
2617 case GL_LOW_FLOAT:
2618 case GL_MEDIUM_FLOAT:
2619 case GL_HIGH_FLOAT:
2620 case GL_LOW_INT:
2621 case GL_MEDIUM_INT:
2622 case GL_HIGH_INT:
2623 break;
2624 default:
2625 synthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2626 return nullptr;
2627 }
2628
2629 GLint range[2] = {0, 0};
2630 GLint precision = 0;
2631 webContext()->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2632 return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2633 }
2634
getShaderSource(WebGLShader * shader)2635 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader)
2636 {
2637 if (isContextLost())
2638 return String();
2639 if (!validateWebGLObject("getShaderSource", shader))
2640 return "";
2641 return ensureNotNull(shader->source());
2642 }
2643
getSupportedExtensions()2644 Nullable<Vector<String> > WebGLRenderingContextBase::getSupportedExtensions()
2645 {
2646 if (isContextLost())
2647 return Nullable<Vector<String> >();
2648
2649 Vector<String> result;
2650
2651 for (size_t i = 0; i < m_extensions.size(); ++i) {
2652 ExtensionTracker* tracker = m_extensions[i].get();
2653 if (extensionSupportedAndAllowed(tracker)) {
2654 const char* const* prefixes = tracker->prefixes();
2655 for (; *prefixes; ++prefixes) {
2656 String prefixedName = String(*prefixes) + tracker->extensionName();
2657 result.append(prefixedName);
2658 }
2659 }
2660 }
2661
2662 return result;
2663 }
2664
getTexParameter(GLenum target,GLenum pname)2665 WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GLenum target, GLenum pname)
2666 {
2667 if (isContextLost())
2668 return WebGLGetInfo();
2669 WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2670 if (!tex)
2671 return WebGLGetInfo();
2672 switch (pname) {
2673 case GL_TEXTURE_MAG_FILTER:
2674 case GL_TEXTURE_MIN_FILTER:
2675 case GL_TEXTURE_WRAP_S:
2676 case GL_TEXTURE_WRAP_T:
2677 {
2678 GLint value = 0;
2679 webContext()->getTexParameteriv(target, pname, &value);
2680 return WebGLGetInfo(static_cast<unsigned>(value));
2681 }
2682 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2683 if (extensionEnabled(EXTTextureFilterAnisotropicName)) {
2684 GLfloat value = 0.f;
2685 webContext()->getTexParameterfv(target, pname, &value);
2686 return WebGLGetInfo(value);
2687 }
2688 synthesizeGLError(GL_INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2689 return WebGLGetInfo();
2690 default:
2691 synthesizeGLError(GL_INVALID_ENUM, "getTexParameter", "invalid parameter name");
2692 return WebGLGetInfo();
2693 }
2694 }
2695
getUniform(WebGLProgram * program,const WebGLUniformLocation * uniformLocation)2696 WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation)
2697 {
2698 if (isContextLost() || !validateWebGLObject("getUniform", program))
2699 return WebGLGetInfo();
2700 if (!uniformLocation || uniformLocation->program() != program) {
2701 synthesizeGLError(GL_INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2702 return WebGLGetInfo();
2703 }
2704 GLint location = uniformLocation->location();
2705
2706 // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2707 GLint activeUniforms = 0;
2708 webContext()->getProgramiv(objectOrZero(program), GL_ACTIVE_UNIFORMS, &activeUniforms);
2709 for (GLint i = 0; i < activeUniforms; i++) {
2710 blink::WebGraphicsContext3D::ActiveInfo info;
2711 if (!webContext()->getActiveUniform(objectOrZero(program), i, info))
2712 return WebGLGetInfo();
2713 String name = info.name;
2714 StringBuilder nameBuilder;
2715 // Strip "[0]" from the name if it's an array.
2716 if (info.size > 1 && name.endsWith("[0]"))
2717 info.name = name.left(name.length() - 3);
2718 // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2719 for (GLint index = 0; index < info.size; ++index) {
2720 nameBuilder.clear();
2721 nameBuilder.append(info.name);
2722 if (info.size > 1 && index >= 1) {
2723 nameBuilder.append('[');
2724 nameBuilder.appendNumber(index);
2725 nameBuilder.append(']');
2726 }
2727 // Now need to look this up by name again to find its location
2728 GLint loc = webContext()->getUniformLocation(objectOrZero(program), nameBuilder.toString().utf8().data());
2729 if (loc == location) {
2730 // Found it. Use the type in the ActiveInfo to determine the return type.
2731 GLenum baseType;
2732 unsigned length;
2733 switch (info.type) {
2734 case GL_BOOL:
2735 baseType = GL_BOOL;
2736 length = 1;
2737 break;
2738 case GL_BOOL_VEC2:
2739 baseType = GL_BOOL;
2740 length = 2;
2741 break;
2742 case GL_BOOL_VEC3:
2743 baseType = GL_BOOL;
2744 length = 3;
2745 break;
2746 case GL_BOOL_VEC4:
2747 baseType = GL_BOOL;
2748 length = 4;
2749 break;
2750 case GL_INT:
2751 baseType = GL_INT;
2752 length = 1;
2753 break;
2754 case GL_INT_VEC2:
2755 baseType = GL_INT;
2756 length = 2;
2757 break;
2758 case GL_INT_VEC3:
2759 baseType = GL_INT;
2760 length = 3;
2761 break;
2762 case GL_INT_VEC4:
2763 baseType = GL_INT;
2764 length = 4;
2765 break;
2766 case GL_FLOAT:
2767 baseType = GL_FLOAT;
2768 length = 1;
2769 break;
2770 case GL_FLOAT_VEC2:
2771 baseType = GL_FLOAT;
2772 length = 2;
2773 break;
2774 case GL_FLOAT_VEC3:
2775 baseType = GL_FLOAT;
2776 length = 3;
2777 break;
2778 case GL_FLOAT_VEC4:
2779 baseType = GL_FLOAT;
2780 length = 4;
2781 break;
2782 case GL_FLOAT_MAT2:
2783 baseType = GL_FLOAT;
2784 length = 4;
2785 break;
2786 case GL_FLOAT_MAT3:
2787 baseType = GL_FLOAT;
2788 length = 9;
2789 break;
2790 case GL_FLOAT_MAT4:
2791 baseType = GL_FLOAT;
2792 length = 16;
2793 break;
2794 case GL_SAMPLER_2D:
2795 case GL_SAMPLER_CUBE:
2796 baseType = GL_INT;
2797 length = 1;
2798 break;
2799 default:
2800 // Can't handle this type
2801 synthesizeGLError(GL_INVALID_VALUE, "getUniform", "unhandled type");
2802 return WebGLGetInfo();
2803 }
2804 switch (baseType) {
2805 case GL_FLOAT: {
2806 GLfloat value[16] = {0};
2807 webContext()->getUniformfv(objectOrZero(program), location, value);
2808 if (length == 1)
2809 return WebGLGetInfo(value[0]);
2810 return WebGLGetInfo(Float32Array::create(value, length));
2811 }
2812 case GL_INT: {
2813 GLint value[4] = {0};
2814 webContext()->getUniformiv(objectOrZero(program), location, value);
2815 if (length == 1)
2816 return WebGLGetInfo(value[0]);
2817 return WebGLGetInfo(Int32Array::create(value, length));
2818 }
2819 case GL_BOOL: {
2820 GLint value[4] = {0};
2821 webContext()->getUniformiv(objectOrZero(program), location, value);
2822 if (length > 1) {
2823 bool boolValue[16] = {0};
2824 for (unsigned j = 0; j < length; j++)
2825 boolValue[j] = static_cast<bool>(value[j]);
2826 return WebGLGetInfo(boolValue, length);
2827 }
2828 return WebGLGetInfo(static_cast<bool>(value[0]));
2829 }
2830 default:
2831 notImplemented();
2832 }
2833 }
2834 }
2835 }
2836 // If we get here, something went wrong in our unfortunately complex logic above
2837 synthesizeGLError(GL_INVALID_VALUE, "getUniform", "unknown error");
2838 return WebGLGetInfo();
2839 }
2840
getUniformLocation(WebGLProgram * program,const String & name)2841 PassRefPtrWillBeRawPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name)
2842 {
2843 if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
2844 return nullptr;
2845 if (!validateLocationLength("getUniformLocation", name))
2846 return nullptr;
2847 if (!validateString("getUniformLocation", name))
2848 return nullptr;
2849 if (isPrefixReserved(name))
2850 return nullptr;
2851 if (!program->linkStatus()) {
2852 synthesizeGLError(GL_INVALID_OPERATION, "getUniformLocation", "program not linked");
2853 return nullptr;
2854 }
2855 GLint uniformLocation = webContext()->getUniformLocation(objectOrZero(program), name.utf8().data());
2856 if (uniformLocation == -1)
2857 return nullptr;
2858 return WebGLUniformLocation::create(program, uniformLocation);
2859 }
2860
getVertexAttrib(GLuint index,GLenum pname)2861 WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GLuint index, GLenum pname)
2862 {
2863 if (isContextLost())
2864 return WebGLGetInfo();
2865 if (index >= m_maxVertexAttribs) {
2866 synthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib", "index out of range");
2867 return WebGLGetInfo();
2868 }
2869 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2870
2871 if (extensionEnabled(ANGLEInstancedArraysName) && pname == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
2872 return WebGLGetInfo(state.divisor);
2873
2874 switch (pname) {
2875 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2876 if (!state.bufferBinding || !state.bufferBinding->object())
2877 return WebGLGetInfo();
2878 return WebGLGetInfo(PassRefPtrWillBeRawPtr<WebGLBuffer>(state.bufferBinding.get()));
2879 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
2880 return WebGLGetInfo(state.enabled);
2881 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
2882 return WebGLGetInfo(state.normalized);
2883 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
2884 return WebGLGetInfo(state.size);
2885 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
2886 return WebGLGetInfo(state.originalStride);
2887 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
2888 return WebGLGetInfo(state.type);
2889 case GL_CURRENT_VERTEX_ATTRIB:
2890 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2891 default:
2892 synthesizeGLError(GL_INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
2893 return WebGLGetInfo();
2894 }
2895 }
2896
getVertexAttribOffset(GLuint index,GLenum pname)2897 long long WebGLRenderingContextBase::getVertexAttribOffset(GLuint index, GLenum pname)
2898 {
2899 if (isContextLost())
2900 return 0;
2901 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) {
2902 synthesizeGLError(GL_INVALID_ENUM, "getVertexAttribOffset", "invalid parameter name");
2903 return 0;
2904 }
2905 GLsizeiptr result = webContext()->getVertexAttribOffset(index, pname);
2906 return static_cast<long long>(result);
2907 }
2908
hint(GLenum target,GLenum mode)2909 void WebGLRenderingContextBase::hint(GLenum target, GLenum mode)
2910 {
2911 if (isContextLost())
2912 return;
2913 bool isValid = false;
2914 switch (target) {
2915 case GL_GENERATE_MIPMAP_HINT:
2916 isValid = true;
2917 break;
2918 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2919 if (extensionEnabled(OESStandardDerivativesName))
2920 isValid = true;
2921 break;
2922 }
2923 if (!isValid) {
2924 synthesizeGLError(GL_INVALID_ENUM, "hint", "invalid target");
2925 return;
2926 }
2927 webContext()->hint(target, mode);
2928 }
2929
isBuffer(WebGLBuffer * buffer)2930 GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
2931 {
2932 if (!buffer || isContextLost())
2933 return 0;
2934
2935 if (!buffer->hasEverBeenBound())
2936 return 0;
2937
2938 return webContext()->isBuffer(buffer->object());
2939 }
2940
isContextLost() const2941 bool WebGLRenderingContextBase::isContextLost() const
2942 {
2943 return m_contextLostMode != NotLostContext;
2944 }
2945
isEnabled(GLenum cap)2946 GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap)
2947 {
2948 if (isContextLost() || !validateCapability("isEnabled", cap))
2949 return 0;
2950 if (cap == GL_STENCIL_TEST)
2951 return m_stencilEnabled;
2952 return webContext()->isEnabled(cap);
2953 }
2954
isFramebuffer(WebGLFramebuffer * framebuffer)2955 GLboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
2956 {
2957 if (!framebuffer || isContextLost())
2958 return 0;
2959
2960 if (!framebuffer->hasEverBeenBound())
2961 return 0;
2962
2963 return webContext()->isFramebuffer(framebuffer->object());
2964 }
2965
isProgram(WebGLProgram * program)2966 GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
2967 {
2968 if (!program || isContextLost())
2969 return 0;
2970
2971 return webContext()->isProgram(program->object());
2972 }
2973
isRenderbuffer(WebGLRenderbuffer * renderbuffer)2974 GLboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2975 {
2976 if (!renderbuffer || isContextLost())
2977 return 0;
2978
2979 if (!renderbuffer->hasEverBeenBound())
2980 return 0;
2981
2982 return webContext()->isRenderbuffer(renderbuffer->object());
2983 }
2984
isShader(WebGLShader * shader)2985 GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
2986 {
2987 if (!shader || isContextLost())
2988 return 0;
2989
2990 return webContext()->isShader(shader->object());
2991 }
2992
isTexture(WebGLTexture * texture)2993 GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
2994 {
2995 if (!texture || isContextLost())
2996 return 0;
2997
2998 if (!texture->hasEverBeenBound())
2999 return 0;
3000
3001 return webContext()->isTexture(texture->object());
3002 }
3003
lineWidth(GLfloat width)3004 void WebGLRenderingContextBase::lineWidth(GLfloat width)
3005 {
3006 if (isContextLost())
3007 return;
3008 webContext()->lineWidth(width);
3009 }
3010
linkProgram(WebGLProgram * program)3011 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program)
3012 {
3013 if (isContextLost() || !validateWebGLObject("linkProgram", program))
3014 return;
3015
3016 webContext()->linkProgram(objectOrZero(program));
3017 program->increaseLinkCount();
3018 }
3019
pixelStorei(GLenum pname,GLint param)3020 void WebGLRenderingContextBase::pixelStorei(GLenum pname, GLint param)
3021 {
3022 if (isContextLost())
3023 return;
3024 switch (pname) {
3025 case GC3D_UNPACK_FLIP_Y_WEBGL:
3026 m_unpackFlipY = param;
3027 break;
3028 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3029 m_unpackPremultiplyAlpha = param;
3030 break;
3031 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
3032 if (static_cast<GLenum>(param) == GC3D_BROWSER_DEFAULT_WEBGL || param == GL_NONE) {
3033 m_unpackColorspaceConversion = static_cast<GLenum>(param);
3034 } else {
3035 synthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
3036 return;
3037 }
3038 break;
3039 case GL_PACK_ALIGNMENT:
3040 case GL_UNPACK_ALIGNMENT:
3041 if (param == 1 || param == 2 || param == 4 || param == 8) {
3042 if (pname == GL_PACK_ALIGNMENT) {
3043 m_packAlignment = param;
3044 drawingBuffer()->setPackAlignment(param);
3045 } else { // GL_UNPACK_ALIGNMENT:
3046 m_unpackAlignment = param;
3047 }
3048 webContext()->pixelStorei(pname, param);
3049 } else {
3050 synthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
3051 return;
3052 }
3053 break;
3054 default:
3055 synthesizeGLError(GL_INVALID_ENUM, "pixelStorei", "invalid parameter name");
3056 return;
3057 }
3058 }
3059
polygonOffset(GLfloat factor,GLfloat units)3060 void WebGLRenderingContextBase::polygonOffset(GLfloat factor, GLfloat units)
3061 {
3062 if (isContextLost())
3063 return;
3064 webContext()->polygonOffset(factor, units);
3065 }
3066
readPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,ArrayBufferView * pixels)3067 void WebGLRenderingContextBase::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView* pixels)
3068 {
3069 if (isContextLost())
3070 return;
3071 // Due to WebGL's same-origin restrictions, it is not possible to
3072 // taint the origin using the WebGL API.
3073 ASSERT(canvas()->originClean());
3074 // Validate input parameters.
3075 if (!pixels) {
3076 synthesizeGLError(GL_INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
3077 return;
3078 }
3079 switch (format) {
3080 case GL_ALPHA:
3081 case GL_RGB:
3082 case GL_RGBA:
3083 break;
3084 default:
3085 synthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid format");
3086 return;
3087 }
3088
3089 ArrayBufferView::ViewType expectedViewType;
3090
3091 switch (type) {
3092 case GL_UNSIGNED_BYTE:
3093 expectedViewType = ArrayBufferView::TypeUint8;
3094 break;
3095 case GL_UNSIGNED_SHORT_5_6_5:
3096 case GL_UNSIGNED_SHORT_4_4_4_4:
3097 case GL_UNSIGNED_SHORT_5_5_5_1:
3098 expectedViewType = ArrayBufferView::TypeUint16;
3099 break;
3100 case GL_FLOAT:
3101 expectedViewType = ArrayBufferView::TypeFloat32;
3102 break;
3103 case GL_HALF_FLOAT_OES:
3104 expectedViewType = ArrayBufferView::TypeUint16;
3105 break;
3106 default:
3107 synthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
3108 return;
3109 }
3110 if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) {
3111 // Check against the implementation color read format and type.
3112 blink::WGC3Dint implFormat = 0, implType = 0;
3113 webContext()->getIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &implFormat);
3114 webContext()->getIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &implType);
3115 if (!implFormat || !implType || format != static_cast<GLenum>(implFormat) || type != static_cast<GLenum>(implType)) {
3116 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "format/type not RGBA/UNSIGNED_BYTE or implementation-defined values");
3117 return;
3118 }
3119 }
3120 // Validate array type against pixel type.
3121 if (pixels->type() != expectedViewType) {
3122 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "ArrayBufferView was the wrong type for the pixel format");
3123 return;
3124 }
3125 const char* reason = "framebuffer incomplete";
3126 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
3127 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
3128 return;
3129 }
3130 // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3131 unsigned totalBytesRequired = 0;
3132 unsigned padding = 0;
3133 GLenum error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3134 if (error != GL_NO_ERROR) {
3135 synthesizeGLError(error, "readPixels", "invalid dimensions");
3136 return;
3137 }
3138 if (pixels->byteLength() < totalBytesRequired) {
3139 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3140 return;
3141 }
3142
3143 clearIfComposited();
3144 void* data = pixels->baseAddress();
3145
3146 {
3147 ScopedDrawingBufferBinder binder(drawingBuffer(), m_framebufferBinding.get());
3148 webContext()->readPixels(x, y, width, height, format, type, data);
3149 }
3150
3151 #if OS(MACOSX)
3152 // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
3153 // when alpha is off, readPixels should set alpha to 255 instead of 0.
3154 if (!m_framebufferBinding && !drawingBuffer()->getActualAttributes().alpha) {
3155 unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
3156 for (GLsizei iy = 0; iy < height; ++iy) {
3157 for (GLsizei ix = 0; ix < width; ++ix) {
3158 pixels[3] = 255;
3159 pixels += 4;
3160 }
3161 pixels += padding;
3162 }
3163 }
3164 #endif
3165 }
3166
renderbufferStorage(GLenum target,GLenum internalformat,GLsizei width,GLsizei height)3167 void WebGLRenderingContextBase::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
3168 {
3169 if (isContextLost())
3170 return;
3171 if (target != GL_RENDERBUFFER) {
3172 synthesizeGLError(GL_INVALID_ENUM, "renderbufferStorage", "invalid target");
3173 return;
3174 }
3175 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
3176 synthesizeGLError(GL_INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
3177 return;
3178 }
3179 if (!validateSize("renderbufferStorage", width, height))
3180 return;
3181 switch (internalformat) {
3182 case GL_DEPTH_COMPONENT16:
3183 case GL_RGBA4:
3184 case GL_RGB5_A1:
3185 case GL_RGB565:
3186 case GL_STENCIL_INDEX8:
3187 webContext()->renderbufferStorage(target, internalformat, width, height);
3188 m_renderbufferBinding->setInternalFormat(internalformat);
3189 m_renderbufferBinding->setSize(width, height);
3190 m_renderbufferBinding->deleteEmulatedStencilBuffer(webContext());
3191 break;
3192 case GL_DEPTH_STENCIL_OES:
3193 if (isDepthStencilSupported()) {
3194 webContext()->renderbufferStorage(target, GL_DEPTH24_STENCIL8_OES, width, height);
3195 } else {
3196 WebGLRenderbuffer* emulatedStencilBuffer = ensureEmulatedStencilBuffer(target, m_renderbufferBinding.get());
3197 if (!emulatedStencilBuffer) {
3198 synthesizeGLError(GL_OUT_OF_MEMORY, "renderbufferStorage", "out of memory");
3199 return;
3200 }
3201 webContext()->renderbufferStorage(target, GL_DEPTH_COMPONENT16, width, height);
3202 webContext()->bindRenderbuffer(target, objectOrZero(emulatedStencilBuffer));
3203 webContext()->renderbufferStorage(target, GL_STENCIL_INDEX8, width, height);
3204 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get()));
3205 emulatedStencilBuffer->setSize(width, height);
3206 emulatedStencilBuffer->setInternalFormat(GL_STENCIL_INDEX8);
3207 }
3208 m_renderbufferBinding->setSize(width, height);
3209 m_renderbufferBinding->setInternalFormat(internalformat);
3210 break;
3211 default:
3212 synthesizeGLError(GL_INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
3213 return;
3214 }
3215 applyStencilTest();
3216 }
3217
sampleCoverage(GLfloat value,GLboolean invert)3218 void WebGLRenderingContextBase::sampleCoverage(GLfloat value, GLboolean invert)
3219 {
3220 if (isContextLost())
3221 return;
3222 webContext()->sampleCoverage(value, invert);
3223 }
3224
scissor(GLint x,GLint y,GLsizei width,GLsizei height)3225 void WebGLRenderingContextBase::scissor(GLint x, GLint y, GLsizei width, GLsizei height)
3226 {
3227 if (isContextLost())
3228 return;
3229 if (!validateSize("scissor", width, height))
3230 return;
3231 webContext()->scissor(x, y, width, height);
3232 }
3233
shaderSource(WebGLShader * shader,const String & string)3234 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string)
3235 {
3236 if (isContextLost() || !validateWebGLObject("shaderSource", shader))
3237 return;
3238 String stringWithoutComments = StripComments(string).result();
3239 if (!validateString("shaderSource", stringWithoutComments))
3240 return;
3241 shader->setSource(string);
3242 webContext()->shaderSource(objectOrZero(shader), stringWithoutComments.utf8().data());
3243 }
3244
stencilFunc(GLenum func,GLint ref,GLuint mask)3245 void WebGLRenderingContextBase::stencilFunc(GLenum func, GLint ref, GLuint mask)
3246 {
3247 if (isContextLost())
3248 return;
3249 if (!validateStencilOrDepthFunc("stencilFunc", func))
3250 return;
3251 m_stencilFuncRef = ref;
3252 m_stencilFuncRefBack = ref;
3253 m_stencilFuncMask = mask;
3254 m_stencilFuncMaskBack = mask;
3255 webContext()->stencilFunc(func, ref, mask);
3256 }
3257
stencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask)3258 void WebGLRenderingContextBase::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
3259 {
3260 if (isContextLost())
3261 return;
3262 if (!validateStencilOrDepthFunc("stencilFuncSeparate", func))
3263 return;
3264 switch (face) {
3265 case GL_FRONT_AND_BACK:
3266 m_stencilFuncRef = ref;
3267 m_stencilFuncRefBack = ref;
3268 m_stencilFuncMask = mask;
3269 m_stencilFuncMaskBack = mask;
3270 break;
3271 case GL_FRONT:
3272 m_stencilFuncRef = ref;
3273 m_stencilFuncMask = mask;
3274 break;
3275 case GL_BACK:
3276 m_stencilFuncRefBack = ref;
3277 m_stencilFuncMaskBack = mask;
3278 break;
3279 default:
3280 synthesizeGLError(GL_INVALID_ENUM, "stencilFuncSeparate", "invalid face");
3281 return;
3282 }
3283 webContext()->stencilFuncSeparate(face, func, ref, mask);
3284 }
3285
stencilMask(GLuint mask)3286 void WebGLRenderingContextBase::stencilMask(GLuint mask)
3287 {
3288 if (isContextLost())
3289 return;
3290 m_stencilMask = mask;
3291 m_stencilMaskBack = mask;
3292 webContext()->stencilMask(mask);
3293 }
3294
stencilMaskSeparate(GLenum face,GLuint mask)3295 void WebGLRenderingContextBase::stencilMaskSeparate(GLenum face, GLuint mask)
3296 {
3297 if (isContextLost())
3298 return;
3299 switch (face) {
3300 case GL_FRONT_AND_BACK:
3301 m_stencilMask = mask;
3302 m_stencilMaskBack = mask;
3303 break;
3304 case GL_FRONT:
3305 m_stencilMask = mask;
3306 break;
3307 case GL_BACK:
3308 m_stencilMaskBack = mask;
3309 break;
3310 default:
3311 synthesizeGLError(GL_INVALID_ENUM, "stencilMaskSeparate", "invalid face");
3312 return;
3313 }
3314 webContext()->stencilMaskSeparate(face, mask);
3315 }
3316
stencilOp(GLenum fail,GLenum zfail,GLenum zpass)3317 void WebGLRenderingContextBase::stencilOp(GLenum fail, GLenum zfail, GLenum zpass)
3318 {
3319 if (isContextLost())
3320 return;
3321 webContext()->stencilOp(fail, zfail, zpass);
3322 }
3323
stencilOpSeparate(GLenum face,GLenum fail,GLenum zfail,GLenum zpass)3324 void WebGLRenderingContextBase::stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
3325 {
3326 if (isContextLost())
3327 return;
3328 webContext()->stencilOpSeparate(face, fail, zfail, zpass);
3329 }
3330
convertTexInternalFormat(GLenum internalformat,GLenum type)3331 GLenum WebGLRenderingContextBase::convertTexInternalFormat(GLenum internalformat, GLenum type)
3332 {
3333 // Convert to sized internal formats that are renderable with GL_CHROMIUM_color_buffer_float_rgb(a).
3334 if (type == GL_FLOAT && internalformat == GL_RGBA
3335 && extensionsUtil()->isExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"))
3336 return GL_RGBA32F_EXT;
3337 if (type == GL_FLOAT && internalformat == GL_RGB
3338 && extensionsUtil()->isExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgb"))
3339 return GL_RGB32F_EXT;
3340 return internalformat;
3341 }
3342
texImage2DBase(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels,ExceptionState & exceptionState)3343 void WebGLRenderingContextBase::texImage2DBase(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels, ExceptionState& exceptionState)
3344 {
3345 // All calling functions check isContextLost, so a duplicate check is not needed here.
3346 // FIXME: Handle errors.
3347 WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3348 ASSERT(validateTexFuncParameters("texImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, format, type));
3349 ASSERT(tex);
3350 ASSERT(!level || !WebGLTexture::isNPOT(width, height));
3351 ASSERT(!pixels || validateSettableTexFormat("texImage2D", internalformat));
3352 webContext()->texImage2D(target, level, convertTexInternalFormat(internalformat, type), width, height, border, format, type, pixels);
3353 tex->setLevelInfo(target, level, internalformat, width, height, type);
3354 }
3355
texImage2DImpl(GLenum target,GLint level,GLenum internalformat,GLenum format,GLenum type,Image * image,WebGLImageConversion::ImageHtmlDomSource domSource,bool flipY,bool premultiplyAlpha,ExceptionState & exceptionState)3356 void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionState& exceptionState)
3357 {
3358 // All calling functions check isContextLost, so a duplicate check is not needed here.
3359 Vector<uint8_t> data;
3360 WebGLImageConversion::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GL_NONE);
3361 if (!imageExtractor.extractSucceeded()) {
3362 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data");
3363 return;
3364 }
3365 WebGLImageConversion::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3366 WebGLImageConversion::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3367 const void* imagePixelData = imageExtractor.imagePixelData();
3368
3369 bool needConversion = true;
3370 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::DataFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNothing && !flipY)
3371 needConversion = false;
3372 else {
3373 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3374 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "packImage error");
3375 return;
3376 }
3377 }
3378
3379 if (m_unpackAlignment != 1)
3380 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3381 texImage2DBase(target, level, internalformat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), 0, format, type, needConversion ? data.data() : imagePixelData, exceptionState);
3382 if (m_unpackAlignment != 1)
3383 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3384 }
3385
validateTexFunc(const char * functionName,TexFuncValidationFunctionType functionType,TexFuncValidationSourceType sourceType,GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,GLint xoffset,GLint yoffset)3386 bool WebGLRenderingContextBase::validateTexFunc(const char* functionName, TexFuncValidationFunctionType functionType, TexFuncValidationSourceType sourceType, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint xoffset, GLint yoffset)
3387 {
3388 if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
3389 return false;
3390
3391 WebGLTexture* texture = validateTextureBinding(functionName, target, true);
3392 if (!texture)
3393 return false;
3394
3395 if (functionType == NotTexSubImage2D) {
3396 if (level && WebGLTexture::isNPOT(width, height)) {
3397 synthesizeGLError(GL_INVALID_VALUE, functionName, "level > 0 not power of 2");
3398 return false;
3399 }
3400 // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
3401 // by checking if the ArrayBufferView is null or not.
3402 if (sourceType != SourceArrayBufferView) {
3403 if (!validateSettableTexFormat(functionName, format))
3404 return false;
3405 }
3406 } else {
3407 if (!validateSettableTexFormat(functionName, format))
3408 return false;
3409 if (!validateSize(functionName, xoffset, yoffset))
3410 return false;
3411 // Before checking if it is in the range, check if overflow happens first.
3412 if (xoffset + width < 0 || yoffset + height < 0) {
3413 synthesizeGLError(GL_INVALID_VALUE, functionName, "bad dimensions");
3414 return false;
3415 }
3416 if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
3417 synthesizeGLError(GL_INVALID_VALUE, functionName, "dimensions out of range");
3418 return false;
3419 }
3420 if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) {
3421 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type and format do not match texture");
3422 return false;
3423 }
3424 }
3425
3426 return true;
3427 }
3428
validateValueFitNonNegInt32(const char * functionName,const char * paramName,long long value)3429 bool WebGLRenderingContextBase::validateValueFitNonNegInt32(const char* functionName, const char* paramName, long long value)
3430 {
3431 if (value < 0) {
3432 String errorMsg = String(paramName) + " < 0";
3433 synthesizeGLError(GL_INVALID_VALUE, functionName, errorMsg.ascii().data());
3434 return false;
3435 }
3436 if (value > static_cast<long long>(std::numeric_limits<int>::max())) {
3437 String errorMsg = String(paramName) + " more than 32-bit";
3438 synthesizeGLError(GL_INVALID_OPERATION, functionName, errorMsg.ascii().data());
3439 return false;
3440 }
3441 return true;
3442 }
3443
drawImageIntoBuffer(Image * image,int width,int height,const char * functionName)3444 PassRefPtr<Image> WebGLRenderingContextBase::drawImageIntoBuffer(Image* image, int width, int height, const char* functionName)
3445 {
3446 IntSize size(width, height);
3447 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3448 if (!buf) {
3449 synthesizeGLError(GL_OUT_OF_MEMORY, functionName, "out of memory");
3450 return nullptr;
3451 }
3452
3453 IntRect srcRect(IntPoint(), image->size());
3454 IntRect destRect(0, 0, size.width(), size.height());
3455 buf->context()->drawImage(image, destRect, srcRect);
3456 return buf->copyImage(ImageBuffer::fastCopyImageMode());
3457 }
3458
texImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,ArrayBufferView * pixels,ExceptionState & exceptionState)3459 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3460 GLsizei width, GLsizei height, GLint border,
3461 GLenum format, GLenum type, ArrayBufferView* pixels, ExceptionState& exceptionState)
3462 {
3463 if (isContextLost() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed)
3464 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
3465 return;
3466 void* data = pixels ? pixels->baseAddress() : 0;
3467 Vector<uint8_t> tempData;
3468 bool changeUnpackAlignment = false;
3469 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3470 if (!WebGLImageConversion::extractTextureData(width, height, format, type, m_unpackAlignment, m_unpackFlipY, m_unpackPremultiplyAlpha, data, tempData))
3471 return;
3472 data = tempData.data();
3473 changeUnpackAlignment = true;
3474 }
3475 if (changeUnpackAlignment)
3476 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3477 texImage2DBase(target, level, internalformat, width, height, border, format, type, data, exceptionState);
3478 if (changeUnpackAlignment)
3479 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3480 }
3481
texImage2D(GLenum target,GLint level,GLenum internalformat,GLenum format,GLenum type,ImageData * pixels,ExceptionState & exceptionState)3482 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3483 GLenum format, GLenum type, ImageData* pixels, ExceptionState& exceptionState)
3484 {
3485 if (isContextLost() || !pixels || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
3486 return;
3487 Vector<uint8_t> data;
3488 bool needConversion = true;
3489 // The data from ImageData is always of format RGBA8.
3490 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3491 if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GL_RGBA && type == GL_UNSIGNED_BYTE)
3492 needConversion = false;
3493 else {
3494 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixels->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3495 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data");
3496 return;
3497 }
3498 }
3499 if (m_unpackAlignment != 1)
3500 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3501 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), exceptionState);
3502 if (m_unpackAlignment != 1)
3503 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3504 }
3505
texImage2D(GLenum target,GLint level,GLenum internalformat,GLenum format,GLenum type,HTMLImageElement * image,ExceptionState & exceptionState)3506 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3507 GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState)
3508 {
3509 if (isContextLost() || !validateHTMLImageElement("texImage2D", image, exceptionState))
3510 return;
3511
3512 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3513 if (imageForRender->isSVGImage())
3514 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), "texImage2D");
3515
3516 if (!imageForRender || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0))
3517 return;
3518
3519 texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3520 }
3521
texImage2D(GLenum target,GLint level,GLenum internalformat,GLenum format,GLenum type,HTMLCanvasElement * canvas,ExceptionState & exceptionState)3522 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3523 GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
3524 {
3525 if (isContextLost() || !validateHTMLCanvasElement("texImage2D", canvas, exceptionState) || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0))
3526 return;
3527
3528 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3529
3530 // If possible, copy from the canvas element directly to the texture
3531 // via the GPU, without a read-back to system memory.
3532 if (GL_TEXTURE_2D == target && texture) {
3533 ScopedTexture2DRestorer restorer(this);
3534
3535 if (!canvas->is3D()) {
3536 ImageBuffer* buffer = canvas->buffer();
3537 if (buffer && buffer->copyToPlatformTexture(webContext(), texture->object(), internalformat, type,
3538 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3539 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3540 return;
3541 }
3542 } else {
3543 WebGLRenderingContextBase* gl = toWebGLRenderingContextBase(canvas->renderingContext());
3544 ScopedTexture2DRestorer restorer(gl);
3545 if (gl && gl->drawingBuffer()->copyToPlatformTexture(webContext(), texture->object(), internalformat, type,
3546 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3547 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3548 return;
3549 }
3550 }
3551 }
3552
3553 RefPtrWillBeRawPtr<ImageData> imageData = canvas->getImageData();
3554 if (imageData)
3555 texImage2D(target, level, internalformat, format, type, imageData.get(), exceptionState);
3556 else
3557 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3558 }
3559
videoFrameToImage(HTMLVideoElement * video,BackingStoreCopy backingStoreCopy)3560 PassRefPtr<Image> WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy)
3561 {
3562 IntSize size(video->videoWidth(), video->videoHeight());
3563 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3564 if (!buf) {
3565 synthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory");
3566 return nullptr;
3567 }
3568 IntRect destRect(0, 0, size.width(), size.height());
3569 video->paintCurrentFrameInContext(buf->context(), destRect);
3570 return buf->copyImage(backingStoreCopy);
3571 }
3572
texImage2D(GLenum target,GLint level,GLenum internalformat,GLenum format,GLenum type,HTMLVideoElement * video,ExceptionState & exceptionState)3573 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3574 GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState)
3575 {
3576 if (isContextLost() || !validateHTMLVideoElement("texImage2D", video, exceptionState)
3577 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 0, format, type, 0, 0))
3578 return;
3579
3580 // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible.
3581 // Otherwise, it will fall back to the normal SW path.
3582 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3583 if (GL_TEXTURE_2D == target && texture) {
3584 if (video->copyVideoTextureToPlatformTexture(webContext(), texture->object(), level, internalformat, type, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3585 texture->setLevelInfo(target, level, internalformat, video->videoWidth(), video->videoHeight(), type);
3586 return;
3587 }
3588 }
3589
3590 // Try using an accelerated image buffer, this allows YUV conversion to be done on the GPU.
3591 OwnPtr<ImageBufferSurface> surface = adoptPtr(new AcceleratedImageBufferSurface(IntSize(video->videoWidth(), video->videoHeight())));
3592 if (surface->isValid()) {
3593 OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(surface.release()));
3594 if (imageBuffer) {
3595 // The video element paints an RGBA frame into our surface here. By using an AcceleratedImageBufferSurface,
3596 // we enable the WebMediaPlayer implementation to do any necessary color space conversion on the GPU (though it
3597 // may still do a CPU conversion and upload the results).
3598 video->paintCurrentFrameInContext(imageBuffer->context(), IntRect(0, 0, video->videoWidth(), video->videoHeight()));
3599 imageBuffer->context()->canvas()->flush();
3600
3601 // This is a straight GPU-GPU copy, any necessary color space conversion was handled in the paintCurrentFrameInContext() call.
3602 if (imageBuffer->copyToPlatformTexture(webContext(), texture->object(), internalformat, type,
3603 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3604 texture->setLevelInfo(target, level, internalformat, video->videoWidth(), video->videoHeight(), type);
3605 return;
3606 }
3607 }
3608 }
3609
3610 // Normal pure SW path.
3611 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode());
3612 if (!image)
3613 return;
3614 texImage2DImpl(target, level, internalformat, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3615 }
3616
texParameter(GLenum target,GLenum pname,GLfloat paramf,GLint parami,bool isFloat)3617 void WebGLRenderingContextBase::texParameter(GLenum target, GLenum pname, GLfloat paramf, GLint parami, bool isFloat)
3618 {
3619 if (isContextLost())
3620 return;
3621 WebGLTexture* tex = validateTextureBinding("texParameter", target, false);
3622 if (!tex)
3623 return;
3624 switch (pname) {
3625 case GL_TEXTURE_MIN_FILTER:
3626 case GL_TEXTURE_MAG_FILTER:
3627 break;
3628 case GL_TEXTURE_WRAP_S:
3629 case GL_TEXTURE_WRAP_T:
3630 if ((isFloat && paramf != GL_CLAMP_TO_EDGE && paramf != GL_MIRRORED_REPEAT && paramf != GL_REPEAT)
3631 || (!isFloat && parami != GL_CLAMP_TO_EDGE && parami != GL_MIRRORED_REPEAT && parami != GL_REPEAT)) {
3632 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter");
3633 return;
3634 }
3635 break;
3636 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3637 if (!extensionEnabled(EXTTextureFilterAnisotropicName)) {
3638 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled");
3639 return;
3640 }
3641 break;
3642 default:
3643 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter name");
3644 return;
3645 }
3646 if (isFloat) {
3647 tex->setParameterf(pname, paramf);
3648 webContext()->texParameterf(target, pname, paramf);
3649 } else {
3650 tex->setParameteri(pname, parami);
3651 webContext()->texParameteri(target, pname, parami);
3652 }
3653 }
3654
texParameterf(GLenum target,GLenum pname,GLfloat param)3655 void WebGLRenderingContextBase::texParameterf(GLenum target, GLenum pname, GLfloat param)
3656 {
3657 texParameter(target, pname, param, 0, true);
3658 }
3659
texParameteri(GLenum target,GLenum pname,GLint param)3660 void WebGLRenderingContextBase::texParameteri(GLenum target, GLenum pname, GLint param)
3661 {
3662 texParameter(target, pname, 0, param, false);
3663 }
3664
texSubImage2DBase(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels,ExceptionState & exceptionState)3665 void WebGLRenderingContextBase::texSubImage2DBase(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels, ExceptionState& exceptionState)
3666 {
3667 // FIXME: Handle errors.
3668 ASSERT(!isContextLost());
3669 ASSERT(validateTexFuncParameters("texSubImage2D", TexSubImage2D, target, level, format, width, height, 0, format, type));
3670 ASSERT(validateSize("texSubImage2D", xoffset, yoffset));
3671 ASSERT(validateSettableTexFormat("texSubImage2D", format));
3672 WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
3673 if (!tex) {
3674 ASSERT_NOT_REACHED();
3675 return;
3676 }
3677 ASSERT((xoffset + width) >= 0);
3678 ASSERT((yoffset + height) >= 0);
3679 ASSERT(tex->getWidth(target, level) >= (xoffset + width));
3680 ASSERT(tex->getHeight(target, level) >= (yoffset + height));
3681 ASSERT(tex->getInternalFormat(target, level) == format);
3682 ASSERT(tex->getType(target, level) == type);
3683 webContext()->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3684 }
3685
texSubImage2DImpl(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,Image * image,WebGLImageConversion::ImageHtmlDomSource domSource,bool flipY,bool premultiplyAlpha,ExceptionState & exceptionState)3686 void WebGLRenderingContextBase::texSubImage2DImpl(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionState& exceptionState)
3687 {
3688 // All calling functions check isContextLost, so a duplicate check is not needed here.
3689 Vector<uint8_t> data;
3690 WebGLImageConversion::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GL_NONE);
3691 if (!imageExtractor.extractSucceeded()) {
3692 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image");
3693 return;
3694 }
3695 WebGLImageConversion::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3696 WebGLImageConversion::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3697 const void* imagePixelData = imageExtractor.imagePixelData();
3698
3699 bool needConversion = true;
3700 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::DataFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNothing && !flipY)
3701 needConversion = false;
3702 else {
3703 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3704 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data");
3705 return;
3706 }
3707 }
3708
3709 if (m_unpackAlignment != 1)
3710 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3711 texSubImage2DBase(target, level, xoffset, yoffset, imageExtractor.imageWidth(), imageExtractor.imageHeight(), format, type, needConversion ? data.data() : imagePixelData, exceptionState);
3712 if (m_unpackAlignment != 1)
3713 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3714 }
3715
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,ArrayBufferView * pixels,ExceptionState & exceptionState)3716 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3717 GLsizei width, GLsizei height,
3718 GLenum format, GLenum type, ArrayBufferView* pixels, ExceptionState& exceptionState)
3719 {
3720 if (isContextLost() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed)
3721 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceArrayBufferView, target, level, format, width, height, 0, format, type, xoffset, yoffset))
3722 return;
3723 void* data = pixels->baseAddress();
3724 Vector<uint8_t> tempData;
3725 bool changeUnpackAlignment = false;
3726 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3727 if (!WebGLImageConversion::extractTextureData(width, height, format, type,
3728 m_unpackAlignment,
3729 m_unpackFlipY, m_unpackPremultiplyAlpha,
3730 data,
3731 tempData))
3732 return;
3733 data = tempData.data();
3734 changeUnpackAlignment = true;
3735 }
3736 if (changeUnpackAlignment)
3737 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3738 texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, exceptionState);
3739 if (changeUnpackAlignment)
3740 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3741 }
3742
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,ImageData * pixels,ExceptionState & exceptionState)3743 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3744 GLenum format, GLenum type, ImageData* pixels, ExceptionState& exceptionState)
3745 {
3746 if (isContextLost() || !pixels || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageData, target, level, format, pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
3747 return;
3748
3749 Vector<uint8_t> data;
3750 bool needConversion = true;
3751 // The data from ImageData is always of format RGBA8.
3752 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3753 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
3754 needConversion = false;
3755 else {
3756 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixels->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3757 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data");
3758 return;
3759 }
3760 }
3761 if (m_unpackAlignment != 1)
3762 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3763 texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, type, needConversion ? data.data() : pixels->data()->data(), exceptionState);
3764 if (m_unpackAlignment != 1)
3765 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3766 }
3767
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLImageElement * image,ExceptionState & exceptionState)3768 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3769 GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState)
3770 {
3771 if (isContextLost() || !validateHTMLImageElement("texSubImage2D", image, exceptionState))
3772 return;
3773
3774 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3775 if (imageForRender->isSVGImage())
3776 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), "texSubImage2D");
3777
3778 if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLImageElement, target, level, format, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset))
3779 return;
3780
3781 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3782 }
3783
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLCanvasElement * canvas,ExceptionState & exceptionState)3784 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3785 GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
3786 {
3787 if (isContextLost() || !validateHTMLCanvasElement("texSubImage2D", canvas, exceptionState)
3788 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLCanvasElement, target, level, format, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset))
3789 return;
3790
3791 RefPtrWillBeRawPtr<ImageData> imageData = canvas->getImageData();
3792 if (imageData)
3793 texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), exceptionState);
3794 else
3795 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3796 }
3797
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLVideoElement * video,ExceptionState & exceptionState)3798 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3799 GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState)
3800 {
3801 if (isContextLost() || !validateHTMLVideoElement("texSubImage2D", video, exceptionState)
3802 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLVideoElement, target, level, format, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset))
3803 return;
3804
3805 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode());
3806 if (!image)
3807 return;
3808 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3809 }
3810
uniform1f(const WebGLUniformLocation * location,GLfloat x)3811 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GLfloat x)
3812 {
3813 if (isContextLost() || !location)
3814 return;
3815
3816 if (location->program() != m_currentProgram) {
3817 synthesizeGLError(GL_INVALID_OPERATION, "uniform1f", "location not for current program");
3818 return;
3819 }
3820
3821 webContext()->uniform1f(location->location(), x);
3822 }
3823
uniform1fv(const WebGLUniformLocation * location,Float32Array * v)3824 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, Float32Array* v)
3825 {
3826 if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, 1))
3827 return;
3828
3829 webContext()->uniform1fv(location->location(), v->length(), v->data());
3830 }
3831
uniform1fv(const WebGLUniformLocation * location,GLfloat * v,GLsizei size)3832 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3833 {
3834 if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, size, 1))
3835 return;
3836
3837 webContext()->uniform1fv(location->location(), size, v);
3838 }
3839
uniform1i(const WebGLUniformLocation * location,GLint x)3840 void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location, GLint x)
3841 {
3842 if (isContextLost() || !location)
3843 return;
3844
3845 if (location->program() != m_currentProgram) {
3846 synthesizeGLError(GL_INVALID_OPERATION, "uniform1i", "location not for current program");
3847 return;
3848 }
3849
3850 webContext()->uniform1i(location->location(), x);
3851 }
3852
uniform1iv(const WebGLUniformLocation * location,Int32Array * v)3853 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, Int32Array* v)
3854 {
3855 if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, 1))
3856 return;
3857
3858 webContext()->uniform1iv(location->location(), v->length(), v->data());
3859 }
3860
uniform1iv(const WebGLUniformLocation * location,GLint * v,GLsizei size)3861 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3862 {
3863 if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, size, 1))
3864 return;
3865
3866 webContext()->uniform1iv(location->location(), size, v);
3867 }
3868
uniform2f(const WebGLUniformLocation * location,GLfloat x,GLfloat y)3869 void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location, GLfloat x, GLfloat y)
3870 {
3871 if (isContextLost() || !location)
3872 return;
3873
3874 if (location->program() != m_currentProgram) {
3875 synthesizeGLError(GL_INVALID_OPERATION, "uniform2f", "location not for current program");
3876 return;
3877 }
3878
3879 webContext()->uniform2f(location->location(), x, y);
3880 }
3881
uniform2fv(const WebGLUniformLocation * location,Float32Array * v)3882 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, Float32Array* v)
3883 {
3884 if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, 2))
3885 return;
3886
3887 webContext()->uniform2fv(location->location(), v->length() >> 1, v->data());
3888 }
3889
uniform2fv(const WebGLUniformLocation * location,GLfloat * v,GLsizei size)3890 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3891 {
3892 if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, size, 2))
3893 return;
3894
3895 webContext()->uniform2fv(location->location(), size >> 1, v);
3896 }
3897
uniform2i(const WebGLUniformLocation * location,GLint x,GLint y)3898 void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location, GLint x, GLint y)
3899 {
3900 if (isContextLost() || !location)
3901 return;
3902
3903 if (location->program() != m_currentProgram) {
3904 synthesizeGLError(GL_INVALID_OPERATION, "uniform2i", "location not for current program");
3905 return;
3906 }
3907
3908 webContext()->uniform2i(location->location(), x, y);
3909 }
3910
uniform2iv(const WebGLUniformLocation * location,Int32Array * v)3911 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, Int32Array* v)
3912 {
3913 if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, 2))
3914 return;
3915
3916 webContext()->uniform2iv(location->location(), v->length() >> 1, v->data());
3917 }
3918
uniform2iv(const WebGLUniformLocation * location,GLint * v,GLsizei size)3919 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3920 {
3921 if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, size, 2))
3922 return;
3923
3924 webContext()->uniform2iv(location->location(), size >> 1, v);
3925 }
3926
uniform3f(const WebGLUniformLocation * location,GLfloat x,GLfloat y,GLfloat z)3927 void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location, GLfloat x, GLfloat y, GLfloat z)
3928 {
3929 if (isContextLost() || !location)
3930 return;
3931
3932 if (location->program() != m_currentProgram) {
3933 synthesizeGLError(GL_INVALID_OPERATION, "uniform3f", "location not for current program");
3934 return;
3935 }
3936
3937 webContext()->uniform3f(location->location(), x, y, z);
3938 }
3939
uniform3fv(const WebGLUniformLocation * location,Float32Array * v)3940 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, Float32Array* v)
3941 {
3942 if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, 3))
3943 return;
3944
3945 webContext()->uniform3fv(location->location(), v->length() / 3, v->data());
3946 }
3947
uniform3fv(const WebGLUniformLocation * location,GLfloat * v,GLsizei size)3948 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3949 {
3950 if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, size, 3))
3951 return;
3952
3953 webContext()->uniform3fv(location->location(), size / 3, v);
3954 }
3955
uniform3i(const WebGLUniformLocation * location,GLint x,GLint y,GLint z)3956 void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location, GLint x, GLint y, GLint z)
3957 {
3958 if (isContextLost() || !location)
3959 return;
3960
3961 if (location->program() != m_currentProgram) {
3962 synthesizeGLError(GL_INVALID_OPERATION, "uniform3i", "location not for current program");
3963 return;
3964 }
3965
3966 webContext()->uniform3i(location->location(), x, y, z);
3967 }
3968
uniform3iv(const WebGLUniformLocation * location,Int32Array * v)3969 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, Int32Array* v)
3970 {
3971 if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, 3))
3972 return;
3973
3974 webContext()->uniform3iv(location->location(), v->length() / 3, v->data());
3975 }
3976
uniform3iv(const WebGLUniformLocation * location,GLint * v,GLsizei size)3977 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3978 {
3979 if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, size, 3))
3980 return;
3981
3982 webContext()->uniform3iv(location->location(), size / 3, v);
3983 }
3984
uniform4f(const WebGLUniformLocation * location,GLfloat x,GLfloat y,GLfloat z,GLfloat w)3985 void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
3986 {
3987 if (isContextLost() || !location)
3988 return;
3989
3990 if (location->program() != m_currentProgram) {
3991 synthesizeGLError(GL_INVALID_OPERATION, "uniform4f", "location not for current program");
3992 return;
3993 }
3994
3995 webContext()->uniform4f(location->location(), x, y, z, w);
3996 }
3997
uniform4fv(const WebGLUniformLocation * location,Float32Array * v)3998 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, Float32Array* v)
3999 {
4000 if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, 4))
4001 return;
4002
4003 webContext()->uniform4fv(location->location(), v->length() >> 2, v->data());
4004 }
4005
uniform4fv(const WebGLUniformLocation * location,GLfloat * v,GLsizei size)4006 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
4007 {
4008 if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, size, 4))
4009 return;
4010
4011 webContext()->uniform4fv(location->location(), size >> 2, v);
4012 }
4013
uniform4i(const WebGLUniformLocation * location,GLint x,GLint y,GLint z,GLint w)4014 void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location, GLint x, GLint y, GLint z, GLint w)
4015 {
4016 if (isContextLost() || !location)
4017 return;
4018
4019 if (location->program() != m_currentProgram) {
4020 synthesizeGLError(GL_INVALID_OPERATION, "uniform4i", "location not for current program");
4021 return;
4022 }
4023
4024 webContext()->uniform4i(location->location(), x, y, z, w);
4025 }
4026
uniform4iv(const WebGLUniformLocation * location,Int32Array * v)4027 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, Int32Array* v)
4028 {
4029 if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, 4))
4030 return;
4031
4032 webContext()->uniform4iv(location->location(), v->length() >> 2, v->data());
4033 }
4034
uniform4iv(const WebGLUniformLocation * location,GLint * v,GLsizei size)4035 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
4036 {
4037 if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, size, 4))
4038 return;
4039
4040 webContext()->uniform4iv(location->location(), size >> 2, v);
4041 }
4042
uniformMatrix2fv(const WebGLUniformLocation * location,GLboolean transpose,Float32Array * v)4043 void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v)
4044 {
4045 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, 4))
4046 return;
4047 webContext()->uniformMatrix2fv(location->location(), v->length() >> 2, transpose, v->data());
4048 }
4049
uniformMatrix2fv(const WebGLUniformLocation * location,GLboolean transpose,GLfloat * v,GLsizei size)4050 void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size)
4051 {
4052 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, size, 4))
4053 return;
4054 webContext()->uniformMatrix2fv(location->location(), size >> 2, transpose, v);
4055 }
4056
uniformMatrix3fv(const WebGLUniformLocation * location,GLboolean transpose,Float32Array * v)4057 void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v)
4058 {
4059 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, 9))
4060 return;
4061 webContext()->uniformMatrix3fv(location->location(), v->length() / 9, transpose, v->data());
4062 }
4063
uniformMatrix3fv(const WebGLUniformLocation * location,GLboolean transpose,GLfloat * v,GLsizei size)4064 void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size)
4065 {
4066 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, size, 9))
4067 return;
4068 webContext()->uniformMatrix3fv(location->location(), size / 9, transpose, v);
4069 }
4070
uniformMatrix4fv(const WebGLUniformLocation * location,GLboolean transpose,Float32Array * v)4071 void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v)
4072 {
4073 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, 16))
4074 return;
4075 webContext()->uniformMatrix4fv(location->location(), v->length() >> 4, transpose, v->data());
4076 }
4077
uniformMatrix4fv(const WebGLUniformLocation * location,GLboolean transpose,GLfloat * v,GLsizei size)4078 void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size)
4079 {
4080 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, size, 16))
4081 return;
4082 webContext()->uniformMatrix4fv(location->location(), size >> 4, transpose, v);
4083 }
4084
useProgram(WebGLProgram * program)4085 void WebGLRenderingContextBase::useProgram(WebGLProgram* program)
4086 {
4087 bool deleted;
4088 if (!checkObjectToBeBound("useProgram", program, deleted))
4089 return;
4090 if (deleted)
4091 program = 0;
4092 if (program && !program->linkStatus()) {
4093 synthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid");
4094 return;
4095 }
4096 if (m_currentProgram != program) {
4097 if (m_currentProgram)
4098 m_currentProgram->onDetached(webContext());
4099 m_currentProgram = program;
4100 webContext()->useProgram(objectOrZero(program));
4101 if (program)
4102 program->onAttached();
4103 }
4104 }
4105
validateProgram(WebGLProgram * program)4106 void WebGLRenderingContextBase::validateProgram(WebGLProgram* program)
4107 {
4108 if (isContextLost() || !validateWebGLObject("validateProgram", program))
4109 return;
4110 webContext()->validateProgram(objectOrZero(program));
4111 }
4112
vertexAttrib1f(GLuint index,GLfloat v0)4113 void WebGLRenderingContextBase::vertexAttrib1f(GLuint index, GLfloat v0)
4114 {
4115 vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f);
4116 }
4117
vertexAttrib1fv(GLuint index,Float32Array * v)4118 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, Float32Array* v)
4119 {
4120 vertexAttribfvImpl("vertexAttrib1fv", index, v, 1);
4121 }
4122
vertexAttrib1fv(GLuint index,GLfloat * v,GLsizei size)4123 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, GLfloat* v, GLsizei size)
4124 {
4125 vertexAttribfvImpl("vertexAttrib1fv", index, v, size, 1);
4126 }
4127
vertexAttrib2f(GLuint index,GLfloat v0,GLfloat v1)4128 void WebGLRenderingContextBase::vertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1)
4129 {
4130 vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f);
4131 }
4132
vertexAttrib2fv(GLuint index,Float32Array * v)4133 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, Float32Array* v)
4134 {
4135 vertexAttribfvImpl("vertexAttrib2fv", index, v, 2);
4136 }
4137
vertexAttrib2fv(GLuint index,GLfloat * v,GLsizei size)4138 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, GLfloat* v, GLsizei size)
4139 {
4140 vertexAttribfvImpl("vertexAttrib2fv", index, v, size, 2);
4141 }
4142
vertexAttrib3f(GLuint index,GLfloat v0,GLfloat v1,GLfloat v2)4143 void WebGLRenderingContextBase::vertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2)
4144 {
4145 vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f);
4146 }
4147
vertexAttrib3fv(GLuint index,Float32Array * v)4148 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, Float32Array* v)
4149 {
4150 vertexAttribfvImpl("vertexAttrib3fv", index, v, 3);
4151 }
4152
vertexAttrib3fv(GLuint index,GLfloat * v,GLsizei size)4153 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, GLfloat* v, GLsizei size)
4154 {
4155 vertexAttribfvImpl("vertexAttrib3fv", index, v, size, 3);
4156 }
4157
vertexAttrib4f(GLuint index,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3)4158 void WebGLRenderingContextBase::vertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
4159 {
4160 vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3);
4161 }
4162
vertexAttrib4fv(GLuint index,Float32Array * v)4163 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, Float32Array* v)
4164 {
4165 vertexAttribfvImpl("vertexAttrib4fv", index, v, 4);
4166 }
4167
vertexAttrib4fv(GLuint index,GLfloat * v,GLsizei size)4168 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, GLfloat* v, GLsizei size)
4169 {
4170 vertexAttribfvImpl("vertexAttrib4fv", index, v, size, 4);
4171 }
4172
vertexAttribPointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,long long offset)4173 void WebGLRenderingContextBase::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset)
4174 {
4175 if (isContextLost())
4176 return;
4177 switch (type) {
4178 case GL_BYTE:
4179 case GL_UNSIGNED_BYTE:
4180 case GL_SHORT:
4181 case GL_UNSIGNED_SHORT:
4182 case GL_FLOAT:
4183 break;
4184 default:
4185 synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type");
4186 return;
4187 }
4188 if (index >= m_maxVertexAttribs) {
4189 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "index out of range");
4190 return;
4191 }
4192 if (size < 1 || size > 4 || stride < 0 || stride > 255) {
4193 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "bad size or stride");
4194 return;
4195 }
4196 if (!validateValueFitNonNegInt32("vertexAttribPointer", "offset", offset))
4197 return;
4198 if (!m_boundArrayBuffer) {
4199 synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER");
4200 return;
4201 }
4202 unsigned typeSize = sizeInBytes(type);
4203 ASSERT((typeSize & (typeSize - 1)) == 0); // Ensure that the value is POT.
4204 if ((stride & (typeSize - 1)) || (static_cast<GLintptr>(offset) & (typeSize - 1))) {
4205 synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type");
4206 return;
4207 }
4208 GLsizei bytesPerElement = size * typeSize;
4209
4210 m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GLintptr>(offset), m_boundArrayBuffer);
4211 webContext()->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GLintptr>(offset));
4212 }
4213
vertexAttribDivisorANGLE(GLuint index,GLuint divisor)4214 void WebGLRenderingContextBase::vertexAttribDivisorANGLE(GLuint index, GLuint divisor)
4215 {
4216 if (isContextLost())
4217 return;
4218
4219 if (index >= m_maxVertexAttribs) {
4220 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribDivisorANGLE", "index out of range");
4221 return;
4222 }
4223
4224 m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor);
4225 webContext()->vertexAttribDivisorANGLE(index, divisor);
4226 }
4227
viewport(GLint x,GLint y,GLsizei width,GLsizei height)4228 void WebGLRenderingContextBase::viewport(GLint x, GLint y, GLsizei width, GLsizei height)
4229 {
4230 if (isContextLost())
4231 return;
4232 if (!validateSize("viewport", width, height))
4233 return;
4234 webContext()->viewport(x, y, width, height);
4235 }
4236
forceLostContext(LostContextMode mode,AutoRecoveryMethod autoRecoveryMethod)4237 void WebGLRenderingContextBase::forceLostContext(LostContextMode mode, AutoRecoveryMethod autoRecoveryMethod)
4238 {
4239 if (isContextLost()) {
4240 synthesizeGLError(GL_INVALID_OPERATION, "loseContext", "context already lost");
4241 return;
4242 }
4243
4244 m_contextGroup->loseContextGroup(mode, autoRecoveryMethod);
4245 }
4246
loseContextImpl(WebGLRenderingContextBase::LostContextMode mode,AutoRecoveryMethod autoRecoveryMethod)4247 void WebGLRenderingContextBase::loseContextImpl(WebGLRenderingContextBase::LostContextMode mode, AutoRecoveryMethod autoRecoveryMethod)
4248 {
4249 if (isContextLost())
4250 return;
4251
4252 m_contextLostMode = mode;
4253 ASSERT(m_contextLostMode != NotLostContext);
4254 m_autoRecoveryMethod = autoRecoveryMethod;
4255
4256 if (mode == RealLostContext) {
4257 // Inform the embedder that a lost context was received. In response, the embedder might
4258 // decide to take action such as asking the user for permission to use WebGL again.
4259 if (LocalFrame* frame = canvas()->document().frame())
4260 frame->loader().client()->didLoseWebGLContext(webContext()->getGraphicsResetStatusARB());
4261 }
4262
4263 // Make absolutely sure we do not refer to an already-deleted texture or framebuffer.
4264 drawingBuffer()->setTexture2DBinding(0);
4265 drawingBuffer()->setFramebufferBinding(0);
4266
4267 detachAndRemoveAllObjects();
4268
4269 // Lose all the extensions.
4270 for (size_t i = 0; i < m_extensions.size(); ++i) {
4271 ExtensionTracker* tracker = m_extensions[i].get();
4272 tracker->loseExtension();
4273 }
4274
4275 for (size_t i = 0; i < WebGLExtensionNameCount; ++i)
4276 m_extensionEnabled[i] = false;
4277
4278 removeAllCompressedTextureFormats();
4279
4280 if (mode != RealLostContext)
4281 destroyContext();
4282
4283 ConsoleDisplayPreference display = (mode == RealLostContext) ? DisplayInConsole: DontDisplayInConsole;
4284 synthesizeGLError(GC3D_CONTEXT_LOST_WEBGL, "loseContext", "context lost", display);
4285
4286 // Don't allow restoration unless the context lost event has both been
4287 // dispatched and its default behavior prevented.
4288 m_restoreAllowed = false;
4289 deactivateContext(this);
4290 if (m_autoRecoveryMethod == WhenAvailable)
4291 addToEvictedList(this);
4292
4293 // Always defer the dispatch of the context lost event, to implement
4294 // the spec behavior of queueing a task.
4295 m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE);
4296 }
4297
forceRestoreContext()4298 void WebGLRenderingContextBase::forceRestoreContext()
4299 {
4300 if (!isContextLost()) {
4301 synthesizeGLError(GL_INVALID_OPERATION, "restoreContext", "context not lost");
4302 return;
4303 }
4304
4305 if (!m_restoreAllowed) {
4306 if (m_contextLostMode == WebGLLoseContextLostContext)
4307 synthesizeGLError(GL_INVALID_OPERATION, "restoreContext", "context restoration not allowed");
4308 return;
4309 }
4310
4311 if (!m_restoreTimer.isActive())
4312 m_restoreTimer.startOneShot(0, FROM_HERE);
4313 }
4314
platformLayer() const4315 blink::WebLayer* WebGLRenderingContextBase::platformLayer() const
4316 {
4317 return isContextLost() ? 0 : drawingBuffer()->platformLayer();
4318 }
4319
extensionsUtil()4320 Extensions3DUtil* WebGLRenderingContextBase::extensionsUtil()
4321 {
4322 ASSERT(!isContextLost());
4323 if (!m_extensionsUtil)
4324 m_extensionsUtil = Extensions3DUtil::create(webContext());
4325 return m_extensionsUtil.get();
4326 }
4327
removeSharedObject(WebGLSharedObject * object)4328 void WebGLRenderingContextBase::removeSharedObject(WebGLSharedObject* object)
4329 {
4330 m_contextGroup->removeObject(object);
4331 }
4332
addSharedObject(WebGLSharedObject * object)4333 void WebGLRenderingContextBase::addSharedObject(WebGLSharedObject* object)
4334 {
4335 ASSERT(!isContextLost());
4336 m_contextGroup->addObject(object);
4337 }
4338
removeContextObject(WebGLContextObject * object)4339 void WebGLRenderingContextBase::removeContextObject(WebGLContextObject* object)
4340 {
4341 m_contextObjects.remove(object);
4342 }
4343
addContextObject(WebGLContextObject * object)4344 void WebGLRenderingContextBase::addContextObject(WebGLContextObject* object)
4345 {
4346 ASSERT(!isContextLost());
4347 m_contextObjects.add(object);
4348 }
4349
detachAndRemoveAllObjects()4350 void WebGLRenderingContextBase::detachAndRemoveAllObjects()
4351 {
4352 while (m_contextObjects.size() > 0) {
4353 WillBeHeapHashSet<RawPtrWillBeWeakMember<WebGLContextObject> >::iterator it = m_contextObjects.begin();
4354 (*it)->detachContext();
4355 }
4356 }
4357
hasPendingActivity() const4358 bool WebGLRenderingContextBase::hasPendingActivity() const
4359 {
4360 return false;
4361 }
4362
stop()4363 void WebGLRenderingContextBase::stop()
4364 {
4365 if (!isContextLost()) {
4366 // Never attempt to restore the context because the page is being torn down.
4367 forceLostContext(SyntheticLostContext, Manual);
4368 }
4369 }
4370
getBooleanParameter(GLenum pname)4371 WebGLGetInfo WebGLRenderingContextBase::getBooleanParameter(GLenum pname)
4372 {
4373 GLboolean value = 0;
4374 if (!isContextLost())
4375 webContext()->getBooleanv(pname, &value);
4376 return WebGLGetInfo(static_cast<bool>(value));
4377 }
4378
getBooleanArrayParameter(GLenum pname)4379 WebGLGetInfo WebGLRenderingContextBase::getBooleanArrayParameter(GLenum pname)
4380 {
4381 if (pname != GL_COLOR_WRITEMASK) {
4382 notImplemented();
4383 return WebGLGetInfo(0, 0);
4384 }
4385 GLboolean value[4] = {0};
4386 if (!isContextLost())
4387 webContext()->getBooleanv(pname, value);
4388 bool boolValue[4];
4389 for (int ii = 0; ii < 4; ++ii)
4390 boolValue[ii] = static_cast<bool>(value[ii]);
4391 return WebGLGetInfo(boolValue, 4);
4392 }
4393
getFloatParameter(GLenum pname)4394 WebGLGetInfo WebGLRenderingContextBase::getFloatParameter(GLenum pname)
4395 {
4396 GLfloat value = 0;
4397 if (!isContextLost())
4398 webContext()->getFloatv(pname, &value);
4399 return WebGLGetInfo(value);
4400 }
4401
getIntParameter(GLenum pname)4402 WebGLGetInfo WebGLRenderingContextBase::getIntParameter(GLenum pname)
4403 {
4404 GLint value = 0;
4405 if (!isContextLost())
4406 webContext()->getIntegerv(pname, &value);
4407 return WebGLGetInfo(value);
4408 }
4409
getUnsignedIntParameter(GLenum pname)4410 WebGLGetInfo WebGLRenderingContextBase::getUnsignedIntParameter(GLenum pname)
4411 {
4412 GLint value = 0;
4413 if (!isContextLost())
4414 webContext()->getIntegerv(pname, &value);
4415 return WebGLGetInfo(static_cast<unsigned>(value));
4416 }
4417
getWebGLFloatArrayParameter(GLenum pname)4418 WebGLGetInfo WebGLRenderingContextBase::getWebGLFloatArrayParameter(GLenum pname)
4419 {
4420 GLfloat value[4] = {0};
4421 if (!isContextLost())
4422 webContext()->getFloatv(pname, value);
4423 unsigned length = 0;
4424 switch (pname) {
4425 case GL_ALIASED_POINT_SIZE_RANGE:
4426 case GL_ALIASED_LINE_WIDTH_RANGE:
4427 case GL_DEPTH_RANGE:
4428 length = 2;
4429 break;
4430 case GL_BLEND_COLOR:
4431 case GL_COLOR_CLEAR_VALUE:
4432 length = 4;
4433 break;
4434 default:
4435 notImplemented();
4436 }
4437 return WebGLGetInfo(Float32Array::create(value, length));
4438 }
4439
getWebGLIntArrayParameter(GLenum pname)4440 WebGLGetInfo WebGLRenderingContextBase::getWebGLIntArrayParameter(GLenum pname)
4441 {
4442 GLint value[4] = {0};
4443 if (!isContextLost())
4444 webContext()->getIntegerv(pname, value);
4445 unsigned length = 0;
4446 switch (pname) {
4447 case GL_MAX_VIEWPORT_DIMS:
4448 length = 2;
4449 break;
4450 case GL_SCISSOR_BOX:
4451 case GL_VIEWPORT:
4452 length = 4;
4453 break;
4454 default:
4455 notImplemented();
4456 }
4457 return WebGLGetInfo(Int32Array::create(value, length));
4458 }
4459
handleTextureCompleteness(const char * functionName,bool prepareToDraw)4460 void WebGLRenderingContextBase::handleTextureCompleteness(const char* functionName, bool prepareToDraw)
4461 {
4462 // All calling functions check isContextLost, so a duplicate check is not needed here.
4463 bool resetActiveUnit = false;
4464 WebGLTexture::TextureExtensionFlag flag = static_cast<WebGLTexture::TextureExtensionFlag>((extensionEnabled(OESTextureFloatLinearName) ? WebGLTexture::TextureFloatLinearExtensionEnabled : 0)
4465 | (extensionEnabled(OESTextureHalfFloatLinearName) ? WebGLTexture::TextureHalfFloatLinearExtensionEnabled : 0));
4466 for (unsigned ii = 0; ii < m_onePlusMaxNonDefaultTextureUnit; ++ii) {
4467 if ((m_textureUnits[ii].m_texture2DBinding.get() && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag))
4468 || (m_textureUnits[ii].m_textureCubeMapBinding.get() && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))) {
4469 if (ii != m_activeTextureUnit) {
4470 webContext()->activeTexture(GL_TEXTURE0 + ii);
4471 resetActiveUnit = true;
4472 } else if (resetActiveUnit) {
4473 webContext()->activeTexture(GL_TEXTURE0 + ii);
4474 resetActiveUnit = false;
4475 }
4476 WebGLTexture* tex2D;
4477 WebGLTexture* texCubeMap;
4478 if (prepareToDraw) {
4479 String msg(String("texture bound to texture unit ") + String::number(ii)
4480 + " is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'."
4481 + " Or the texture is Float or Half Float type with linear filtering while OES_float_linear or OES_half_float_linear extension is not enabled.");
4482 emitGLWarning(functionName, msg.utf8().data());
4483 tex2D = m_blackTexture2D.get();
4484 texCubeMap = m_blackTextureCubeMap.get();
4485 } else {
4486 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4487 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4488 }
4489 if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag))
4490 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(tex2D));
4491 if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))
4492 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4493 }
4494 }
4495 if (resetActiveUnit)
4496 webContext()->activeTexture(GL_TEXTURE0 + m_activeTextureUnit);
4497 }
4498
createFallbackBlackTextures1x1()4499 void WebGLRenderingContextBase::createFallbackBlackTextures1x1()
4500 {
4501 // All calling functions check isContextLost, so a duplicate check is not needed here.
4502 unsigned char black[] = {0, 0, 0, 255};
4503 m_blackTexture2D = createTexture();
4504 webContext()->bindTexture(GL_TEXTURE_2D, m_blackTexture2D->object());
4505 webContext()->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
4506 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4507 webContext()->bindTexture(GL_TEXTURE_2D, 0);
4508 m_blackTextureCubeMap = createTexture();
4509 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4510 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 1, 1,
4511 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4512 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 1, 1,
4513 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4514 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 1, 1,
4515 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4516 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 1, 1,
4517 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4518 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 1, 1,
4519 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4520 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 1, 1,
4521 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4522 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, 0);
4523 }
4524
isTexInternalFormatColorBufferCombinationValid(GLenum texInternalFormat,GLenum colorBufferFormat)4525 bool WebGLRenderingContextBase::isTexInternalFormatColorBufferCombinationValid(GLenum texInternalFormat, GLenum colorBufferFormat)
4526 {
4527 unsigned need = WebGLImageConversion::getChannelBitsByFormat(texInternalFormat);
4528 unsigned have = WebGLImageConversion::getChannelBitsByFormat(colorBufferFormat);
4529 return (need & have) == need;
4530 }
4531
boundFramebufferColorFormat()4532 GLenum WebGLRenderingContextBase::boundFramebufferColorFormat()
4533 {
4534 if (m_framebufferBinding && m_framebufferBinding->object())
4535 return m_framebufferBinding->colorBufferFormat();
4536 if (m_requestedAttributes->alpha())
4537 return GL_RGBA;
4538 return GL_RGB;
4539 }
4540
validateTextureBinding(const char * functionName,GLenum target,bool useSixEnumsForCubeMap)4541 WebGLTexture* WebGLRenderingContextBase::validateTextureBinding(const char* functionName, GLenum target, bool useSixEnumsForCubeMap)
4542 {
4543 WebGLTexture* tex = 0;
4544 switch (target) {
4545 case GL_TEXTURE_2D:
4546 tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4547 break;
4548 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4549 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4550 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4551 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4552 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4553 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4554 if (!useSixEnumsForCubeMap) {
4555 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target");
4556 return 0;
4557 }
4558 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4559 break;
4560 case GL_TEXTURE_CUBE_MAP:
4561 if (useSixEnumsForCubeMap) {
4562 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target");
4563 return 0;
4564 }
4565 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4566 break;
4567 default:
4568 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target");
4569 return 0;
4570 }
4571 if (!tex)
4572 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no texture");
4573 return tex;
4574 }
4575
validateLocationLength(const char * functionName,const String & string)4576 bool WebGLRenderingContextBase::validateLocationLength(const char* functionName, const String& string)
4577 {
4578 const unsigned maxWebGLLocationLength = 256;
4579 if (string.length() > maxWebGLLocationLength) {
4580 synthesizeGLError(GL_INVALID_VALUE, functionName, "location length > 256");
4581 return false;
4582 }
4583 return true;
4584 }
4585
validateSize(const char * functionName,GLint x,GLint y)4586 bool WebGLRenderingContextBase::validateSize(const char* functionName, GLint x, GLint y)
4587 {
4588 if (x < 0 || y < 0) {
4589 synthesizeGLError(GL_INVALID_VALUE, functionName, "size < 0");
4590 return false;
4591 }
4592 return true;
4593 }
4594
validateString(const char * functionName,const String & string)4595 bool WebGLRenderingContextBase::validateString(const char* functionName, const String& string)
4596 {
4597 for (size_t i = 0; i < string.length(); ++i) {
4598 if (!validateCharacter(string[i])) {
4599 synthesizeGLError(GL_INVALID_VALUE, functionName, "string not ASCII");
4600 return false;
4601 }
4602 }
4603 return true;
4604 }
4605
validateTexFuncFormatAndType(const char * functionName,GLenum format,GLenum type,GLint level)4606 bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, GLenum format, GLenum type, GLint level)
4607 {
4608 switch (format) {
4609 case GL_ALPHA:
4610 case GL_LUMINANCE:
4611 case GL_LUMINANCE_ALPHA:
4612 case GL_RGB:
4613 case GL_RGBA:
4614 break;
4615 case GL_DEPTH_STENCIL_OES:
4616 case GL_DEPTH_COMPONENT:
4617 if (extensionEnabled(WebGLDepthTextureName))
4618 break;
4619 synthesizeGLError(GL_INVALID_ENUM, functionName, "depth texture formats not enabled");
4620 return false;
4621 default:
4622 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture format");
4623 return false;
4624 }
4625
4626 switch (type) {
4627 case GL_UNSIGNED_BYTE:
4628 case GL_UNSIGNED_SHORT_5_6_5:
4629 case GL_UNSIGNED_SHORT_4_4_4_4:
4630 case GL_UNSIGNED_SHORT_5_5_5_1:
4631 break;
4632 case GL_FLOAT:
4633 if (extensionEnabled(OESTextureFloatName))
4634 break;
4635 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4636 return false;
4637 case GL_HALF_FLOAT_OES:
4638 if (extensionEnabled(OESTextureHalfFloatName))
4639 break;
4640 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4641 return false;
4642 case GL_UNSIGNED_INT:
4643 case GL_UNSIGNED_INT_24_8_OES:
4644 case GL_UNSIGNED_SHORT:
4645 if (extensionEnabled(WebGLDepthTextureName))
4646 break;
4647 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4648 return false;
4649 default:
4650 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4651 return false;
4652 }
4653
4654 // Verify that the combination of format and type is supported.
4655 switch (format) {
4656 case GL_ALPHA:
4657 case GL_LUMINANCE:
4658 case GL_LUMINANCE_ALPHA:
4659 if (type != GL_UNSIGNED_BYTE
4660 && type != GL_FLOAT
4661 && type != GL_HALF_FLOAT_OES) {
4662 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for format");
4663 return false;
4664 }
4665 break;
4666 case GL_RGB:
4667 if (type != GL_UNSIGNED_BYTE
4668 && type != GL_UNSIGNED_SHORT_5_6_5
4669 && type != GL_FLOAT
4670 && type != GL_HALF_FLOAT_OES) {
4671 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for RGB format");
4672 return false;
4673 }
4674 break;
4675 case GL_RGBA:
4676 if (type != GL_UNSIGNED_BYTE
4677 && type != GL_UNSIGNED_SHORT_4_4_4_4
4678 && type != GL_UNSIGNED_SHORT_5_5_5_1
4679 && type != GL_FLOAT
4680 && type != GL_HALF_FLOAT_OES) {
4681 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for RGBA format");
4682 return false;
4683 }
4684 break;
4685 case GL_DEPTH_COMPONENT:
4686 if (!extensionEnabled(WebGLDepthTextureName)) {
4687 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
4688 return false;
4689 }
4690 if (type != GL_UNSIGNED_SHORT
4691 && type != GL_UNSIGNED_INT) {
4692 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
4693 return false;
4694 }
4695 if (level > 0) {
4696 synthesizeGLError(GL_INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
4697 return false;
4698 }
4699 break;
4700 case GL_DEPTH_STENCIL_OES:
4701 if (!extensionEnabled(WebGLDepthTextureName)) {
4702 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled");
4703 return false;
4704 }
4705 if (type != GL_UNSIGNED_INT_24_8_OES) {
4706 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format");
4707 return false;
4708 }
4709 if (level > 0) {
4710 synthesizeGLError(GL_INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format");
4711 return false;
4712 }
4713 break;
4714 default:
4715 ASSERT_NOT_REACHED();
4716 }
4717
4718 return true;
4719 }
4720
validateTexFuncLevel(const char * functionName,GLenum target,GLint level)4721 bool WebGLRenderingContextBase::validateTexFuncLevel(const char* functionName, GLenum target, GLint level)
4722 {
4723 if (level < 0) {
4724 synthesizeGLError(GL_INVALID_VALUE, functionName, "level < 0");
4725 return false;
4726 }
4727 switch (target) {
4728 case GL_TEXTURE_2D:
4729 if (level >= m_maxTextureLevel) {
4730 synthesizeGLError(GL_INVALID_VALUE, functionName, "level out of range");
4731 return false;
4732 }
4733 break;
4734 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4735 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4736 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4737 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4738 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4739 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4740 if (level >= m_maxCubeMapTextureLevel) {
4741 synthesizeGLError(GL_INVALID_VALUE, functionName, "level out of range");
4742 return false;
4743 }
4744 break;
4745 }
4746 // This function only checks if level is legal, so we return true and don't
4747 // generate INVALID_ENUM if target is illegal.
4748 return true;
4749 }
4750
validateTexFuncDimensions(const char * functionName,TexFuncValidationFunctionType functionType,GLenum target,GLint level,GLsizei width,GLsizei height)4751 bool WebGLRenderingContextBase::validateTexFuncDimensions(const char* functionName, TexFuncValidationFunctionType functionType,
4752 GLenum target, GLint level, GLsizei width, GLsizei height)
4753 {
4754 if (width < 0 || height < 0) {
4755 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0");
4756 return false;
4757 }
4758
4759 switch (target) {
4760 case GL_TEXTURE_2D:
4761 if (width > (m_maxTextureSize >> level) || height > (m_maxTextureSize >> level)) {
4762 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height out of range");
4763 return false;
4764 }
4765 break;
4766 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4767 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4768 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4769 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4770 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4771 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4772 if (functionType != TexSubImage2D && width != height) {
4773 synthesizeGLError(GL_INVALID_VALUE, functionName, "width != height for cube map");
4774 return false;
4775 }
4776 // No need to check height here. For texImage width == height.
4777 // For texSubImage that will be checked when checking yoffset + height is in range.
4778 if (width > (m_maxCubeMapTextureSize >> level)) {
4779 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height out of range for cube map");
4780 return false;
4781 }
4782 break;
4783 default:
4784 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
4785 return false;
4786 }
4787 return true;
4788 }
4789
validateTexFuncParameters(const char * functionName,TexFuncValidationFunctionType functionType,GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type)4790 bool WebGLRenderingContextBase::validateTexFuncParameters(const char* functionName, TexFuncValidationFunctionType functionType, GLenum target,
4791 GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type)
4792 {
4793 // We absolutely have to validate the format and type combination.
4794 // The texImage2D entry points taking HTMLImage, etc. will produce
4795 // temporary data based on this combination, so it must be legal.
4796 if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level))
4797 return false;
4798
4799 if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height))
4800 return false;
4801
4802 if (format != internalformat) {
4803 synthesizeGLError(GL_INVALID_OPERATION, functionName, "format != internalformat");
4804 return false;
4805 }
4806
4807 if (border) {
4808 synthesizeGLError(GL_INVALID_VALUE, functionName, "border != 0");
4809 return false;
4810 }
4811
4812 return true;
4813 }
4814
validateTexFuncData(const char * functionName,GLint level,GLsizei width,GLsizei height,GLenum format,GLenum type,ArrayBufferView * pixels,NullDisposition disposition)4815 bool WebGLRenderingContextBase::validateTexFuncData(const char* functionName, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView* pixels, NullDisposition disposition)
4816 {
4817 // All calling functions check isContextLost, so a duplicate check is not needed here.
4818 if (!pixels) {
4819 if (disposition == NullAllowed)
4820 return true;
4821 synthesizeGLError(GL_INVALID_VALUE, functionName, "no pixels");
4822 return false;
4823 }
4824
4825 if (!validateTexFuncFormatAndType(functionName, format, type, level))
4826 return false;
4827 if (!validateSettableTexFormat(functionName, format))
4828 return false;
4829
4830 switch (type) {
4831 case GL_UNSIGNED_BYTE:
4832 if (pixels->type() != ArrayBufferView::TypeUint8) {
4833 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array");
4834 return false;
4835 }
4836 break;
4837 case GL_UNSIGNED_SHORT_5_6_5:
4838 case GL_UNSIGNED_SHORT_4_4_4_4:
4839 case GL_UNSIGNED_SHORT_5_5_5_1:
4840 if (pixels->type() != ArrayBufferView::TypeUint16) {
4841 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
4842 return false;
4843 }
4844 break;
4845 case GL_FLOAT: // OES_texture_float
4846 if (pixels->type() != ArrayBufferView::TypeFloat32) {
4847 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array");
4848 return false;
4849 }
4850 break;
4851 case GL_HALF_FLOAT_OES: // OES_texture_half_float
4852 // As per the specification, ArrayBufferView should be null or a Uint16Array when
4853 // OES_texture_half_float is enabled.
4854 if (pixels && pixels->type() != ArrayBufferView::TypeUint16) {
4855 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL and not Uint16Array");
4856 return false;
4857 }
4858 break;
4859 default:
4860 ASSERT_NOT_REACHED();
4861 }
4862
4863 unsigned totalBytesRequired;
4864 GLenum error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
4865 if (error != GL_NO_ERROR) {
4866 synthesizeGLError(error, functionName, "invalid texture dimensions");
4867 return false;
4868 }
4869 if (pixels->byteLength() < totalBytesRequired) {
4870 if (m_unpackAlignment != 1) {
4871 error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0);
4872 if (pixels->byteLength() == totalBytesRequired) {
4873 synthesizeGLError(GL_INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1");
4874 return false;
4875 }
4876 }
4877 synthesizeGLError(GL_INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
4878 return false;
4879 }
4880 return true;
4881 }
4882
validateCompressedTexFormat(GLenum format)4883 bool WebGLRenderingContextBase::validateCompressedTexFormat(GLenum format)
4884 {
4885 return m_compressedTextureFormats.contains(format);
4886 }
4887
validateCompressedTexFuncData(const char * functionName,GLsizei width,GLsizei height,GLenum format,ArrayBufferView * pixels)4888 bool WebGLRenderingContextBase::validateCompressedTexFuncData(const char* functionName, GLsizei width, GLsizei height, GLenum format, ArrayBufferView* pixels)
4889 {
4890 if (!pixels) {
4891 synthesizeGLError(GL_INVALID_VALUE, functionName, "no pixels");
4892 return false;
4893 }
4894 if (width < 0 || height < 0) {
4895 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0");
4896 return false;
4897 }
4898
4899 unsigned bytesRequired = 0;
4900
4901 switch (format) {
4902 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
4903 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
4904 {
4905 const int kBlockWidth = 4;
4906 const int kBlockHeight = 4;
4907 const int kBlockSize = 8;
4908 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
4909 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
4910 int numBlocks = numBlocksAcross * numBlocksDown;
4911 bytesRequired = numBlocks * kBlockSize;
4912 }
4913 break;
4914 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
4915 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
4916 {
4917 const int kBlockWidth = 4;
4918 const int kBlockHeight = 4;
4919 const int kBlockSize = 16;
4920 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
4921 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
4922 int numBlocks = numBlocksAcross * numBlocksDown;
4923 bytesRequired = numBlocks * kBlockSize;
4924 }
4925 break;
4926 case GC3D_COMPRESSED_ATC_RGB_AMD:
4927 case GL_ETC1_RGB8_OES:
4928 {
4929 bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 8;
4930 }
4931 break;
4932 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
4933 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
4934 {
4935 bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 16;
4936 }
4937 break;
4938 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
4939 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
4940 {
4941 bytesRequired = (max(width, 8) * max(height, 8) * 4 + 7) / 8;
4942 }
4943 break;
4944 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
4945 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
4946 {
4947 bytesRequired = (max(width, 16) * max(height, 8) * 2 + 7) / 8;
4948 }
4949 break;
4950 default:
4951 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format");
4952 return false;
4953 }
4954
4955 if (pixels->byteLength() != bytesRequired) {
4956 synthesizeGLError(GL_INVALID_VALUE, functionName, "length of ArrayBufferView is not correct for dimensions");
4957 return false;
4958 }
4959
4960 return true;
4961 }
4962
validateCompressedTexDimensions(const char * functionName,TexFuncValidationFunctionType functionType,GLenum target,GLint level,GLsizei width,GLsizei height,GLenum format)4963 bool WebGLRenderingContextBase::validateCompressedTexDimensions(const char* functionName, TexFuncValidationFunctionType functionType, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format)
4964 {
4965 if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height))
4966 return false;
4967
4968 bool widthValid = false;
4969 bool heightValid = false;
4970
4971 switch (format) {
4972 case GC3D_COMPRESSED_ATC_RGB_AMD:
4973 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
4974 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
4975 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
4976 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
4977 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
4978 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
4979 const int kBlockWidth = 4;
4980 const int kBlockHeight = 4;
4981 widthValid = (level && width == 1) || (level && width == 2) || !(width % kBlockWidth);
4982 heightValid = (level && height == 1) || (level && height == 2) || !(height % kBlockHeight);
4983 break;
4984 }
4985 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
4986 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
4987 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
4988 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
4989 // Must be a power of two
4990 widthValid = (width & (width - 1)) == 0;
4991 heightValid = (height & (height - 1)) == 0;
4992 break;
4993 }
4994 case GL_ETC1_RGB8_OES: {
4995 widthValid = true;
4996 heightValid = true;
4997 break;
4998 }
4999 default:
5000 return false;
5001 }
5002
5003 if (!widthValid || !heightValid) {
5004 synthesizeGLError(GL_INVALID_OPERATION, functionName, "width or height invalid for level");
5005 return false;
5006 }
5007
5008 return true;
5009 }
5010
validateCompressedTexSubDimensions(const char * functionName,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,WebGLTexture * tex)5011 bool WebGLRenderingContextBase::validateCompressedTexSubDimensions(const char* functionName, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, WebGLTexture* tex)
5012 {
5013 if (xoffset < 0 || yoffset < 0) {
5014 synthesizeGLError(GL_INVALID_VALUE, functionName, "xoffset or yoffset < 0");
5015 return false;
5016 }
5017
5018 switch (format) {
5019 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5020 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
5021 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
5022 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
5023 const int kBlockWidth = 4;
5024 const int kBlockHeight = 4;
5025 if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
5026 synthesizeGLError(GL_INVALID_OPERATION, functionName, "xoffset or yoffset not multiple of 4");
5027 return false;
5028 }
5029 if (width - xoffset > tex->getWidth(target, level)
5030 || height - yoffset > tex->getHeight(target, level)) {
5031 synthesizeGLError(GL_INVALID_OPERATION, functionName, "dimensions out of range");
5032 return false;
5033 }
5034 return validateCompressedTexDimensions(functionName, TexSubImage2D, target, level, width, height, format);
5035 }
5036 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
5037 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
5038 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
5039 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
5040 if ((xoffset != 0) || (yoffset != 0)) {
5041 synthesizeGLError(GL_INVALID_OPERATION, functionName, "xoffset and yoffset must be zero");
5042 return false;
5043 }
5044 if (width != tex->getWidth(target, level)
5045 || height != tex->getHeight(target, level)) {
5046 synthesizeGLError(GL_INVALID_OPERATION, functionName, "dimensions must match existing level");
5047 return false;
5048 }
5049 return validateCompressedTexDimensions(functionName, TexSubImage2D, target, level, width, height, format);
5050 }
5051 case GC3D_COMPRESSED_ATC_RGB_AMD:
5052 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
5053 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5054 case GL_ETC1_RGB8_OES: {
5055 synthesizeGLError(GL_INVALID_OPERATION, functionName, "unable to update sub-images with this format");
5056 return false;
5057 }
5058 default:
5059 return false;
5060 }
5061 }
5062
validateDrawMode(const char * functionName,GLenum mode)5063 bool WebGLRenderingContextBase::validateDrawMode(const char* functionName, GLenum mode)
5064 {
5065 switch (mode) {
5066 case GL_POINTS:
5067 case GL_LINE_STRIP:
5068 case GL_LINE_LOOP:
5069 case GL_LINES:
5070 case GL_TRIANGLE_STRIP:
5071 case GL_TRIANGLE_FAN:
5072 case GL_TRIANGLES:
5073 return true;
5074 default:
5075 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid draw mode");
5076 return false;
5077 }
5078 }
5079
validateStencilSettings(const char * functionName)5080 bool WebGLRenderingContextBase::validateStencilSettings(const char* functionName)
5081 {
5082 if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
5083 synthesizeGLError(GL_INVALID_OPERATION, functionName, "front and back stencils settings do not match");
5084 return false;
5085 }
5086 return true;
5087 }
5088
validateStencilOrDepthFunc(const char * functionName,GLenum func)5089 bool WebGLRenderingContextBase::validateStencilOrDepthFunc(const char* functionName, GLenum func)
5090 {
5091 switch (func) {
5092 case GL_NEVER:
5093 case GL_LESS:
5094 case GL_LEQUAL:
5095 case GL_GREATER:
5096 case GL_GEQUAL:
5097 case GL_EQUAL:
5098 case GL_NOTEQUAL:
5099 case GL_ALWAYS:
5100 return true;
5101 default:
5102 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid function");
5103 return false;
5104 }
5105 }
5106
printGLErrorToConsole(const String & message)5107 void WebGLRenderingContextBase::printGLErrorToConsole(const String& message)
5108 {
5109 if (!m_numGLErrorsToConsoleAllowed)
5110 return;
5111
5112 --m_numGLErrorsToConsoleAllowed;
5113 printWarningToConsole(message);
5114
5115 if (!m_numGLErrorsToConsoleAllowed)
5116 printWarningToConsole("WebGL: too many errors, no more errors will be reported to the console for this context.");
5117
5118 return;
5119 }
5120
printWarningToConsole(const String & message)5121 void WebGLRenderingContextBase::printWarningToConsole(const String& message)
5122 {
5123 if (!canvas())
5124 return;
5125 canvas()->document().addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, WarningMessageLevel, message));
5126 }
5127
validateFramebufferFuncParameters(const char * functionName,GLenum target,GLenum attachment)5128 bool WebGLRenderingContextBase::validateFramebufferFuncParameters(const char* functionName, GLenum target, GLenum attachment)
5129 {
5130 if (target != GL_FRAMEBUFFER) {
5131 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
5132 return false;
5133 }
5134 switch (attachment) {
5135 case GL_COLOR_ATTACHMENT0:
5136 case GL_DEPTH_ATTACHMENT:
5137 case GL_STENCIL_ATTACHMENT:
5138 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
5139 break;
5140 default:
5141 if (extensionEnabled(WebGLDrawBuffersName)
5142 && attachment > GL_COLOR_ATTACHMENT0
5143 && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + maxColorAttachments()))
5144 break;
5145 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid attachment");
5146 return false;
5147 }
5148 return true;
5149 }
5150
validateBlendEquation(const char * functionName,GLenum mode)5151 bool WebGLRenderingContextBase::validateBlendEquation(const char* functionName, GLenum mode)
5152 {
5153 switch (mode) {
5154 case GL_FUNC_ADD:
5155 case GL_FUNC_SUBTRACT:
5156 case GL_FUNC_REVERSE_SUBTRACT:
5157 return true;
5158 case GL_MIN_EXT:
5159 case GL_MAX_EXT:
5160 if (extensionEnabled(EXTBlendMinMaxName))
5161 return true;
5162 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid mode");
5163 return false;
5164 default:
5165 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid mode");
5166 return false;
5167 }
5168 }
5169
validateBlendFuncFactors(const char * functionName,GLenum src,GLenum dst)5170 bool WebGLRenderingContextBase::validateBlendFuncFactors(const char* functionName, GLenum src, GLenum dst)
5171 {
5172 if (((src == GL_CONSTANT_COLOR || src == GL_ONE_MINUS_CONSTANT_COLOR)
5173 && (dst == GL_CONSTANT_ALPHA || dst == GL_ONE_MINUS_CONSTANT_ALPHA))
5174 || ((dst == GL_CONSTANT_COLOR || dst == GL_ONE_MINUS_CONSTANT_COLOR)
5175 && (src == GL_CONSTANT_ALPHA || src == GL_ONE_MINUS_CONSTANT_ALPHA))) {
5176 synthesizeGLError(GL_INVALID_OPERATION, functionName, "incompatible src and dst");
5177 return false;
5178 }
5179 return true;
5180 }
5181
validateCapability(const char * functionName,GLenum cap)5182 bool WebGLRenderingContextBase::validateCapability(const char* functionName, GLenum cap)
5183 {
5184 switch (cap) {
5185 case GL_BLEND:
5186 case GL_CULL_FACE:
5187 case GL_DEPTH_TEST:
5188 case GL_DITHER:
5189 case GL_POLYGON_OFFSET_FILL:
5190 case GL_SAMPLE_ALPHA_TO_COVERAGE:
5191 case GL_SAMPLE_COVERAGE:
5192 case GL_SCISSOR_TEST:
5193 case GL_STENCIL_TEST:
5194 return true;
5195 default:
5196 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid capability");
5197 return false;
5198 }
5199 }
5200
validateUniformParameters(const char * functionName,const WebGLUniformLocation * location,Float32Array * v,GLsizei requiredMinSize)5201 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GLsizei requiredMinSize)
5202 {
5203 if (!v) {
5204 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5205 return false;
5206 }
5207 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5208 }
5209
validateUniformParameters(const char * functionName,const WebGLUniformLocation * location,Int32Array * v,GLsizei requiredMinSize)5210 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GLsizei requiredMinSize)
5211 {
5212 if (!v) {
5213 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5214 return false;
5215 }
5216 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5217 }
5218
validateUniformParameters(const char * functionName,const WebGLUniformLocation * location,void * v,GLsizei size,GLsizei requiredMinSize)5219 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GLsizei size, GLsizei requiredMinSize)
5220 {
5221 return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize);
5222 }
5223
validateUniformMatrixParameters(const char * functionName,const WebGLUniformLocation * location,GLboolean transpose,Float32Array * v,GLsizei requiredMinSize)5224 bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v, GLsizei requiredMinSize)
5225 {
5226 if (!v) {
5227 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5228 return false;
5229 }
5230 return validateUniformMatrixParameters(functionName, location, transpose, v->data(), v->length(), requiredMinSize);
5231 }
5232
validateUniformMatrixParameters(const char * functionName,const WebGLUniformLocation * location,GLboolean transpose,void * v,GLsizei size,GLsizei requiredMinSize)5233 bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GLboolean transpose, void* v, GLsizei size, GLsizei requiredMinSize)
5234 {
5235 if (!location)
5236 return false;
5237 if (location->program() != m_currentProgram) {
5238 synthesizeGLError(GL_INVALID_OPERATION, functionName, "location is not from current program");
5239 return false;
5240 }
5241 if (!v) {
5242 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5243 return false;
5244 }
5245 if (transpose) {
5246 synthesizeGLError(GL_INVALID_VALUE, functionName, "transpose not FALSE");
5247 return false;
5248 }
5249 if (size < requiredMinSize || (size % requiredMinSize)) {
5250 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size");
5251 return false;
5252 }
5253 return true;
5254 }
5255
validateBufferDataTarget(const char * functionName,GLenum target)5256 WebGLBuffer* WebGLRenderingContextBase::validateBufferDataTarget(const char* functionName, GLenum target)
5257 {
5258 WebGLBuffer* buffer = 0;
5259 switch (target) {
5260 case GL_ELEMENT_ARRAY_BUFFER:
5261 buffer = m_boundVertexArrayObject->boundElementArrayBuffer().get();
5262 break;
5263 case GL_ARRAY_BUFFER:
5264 buffer = m_boundArrayBuffer.get();
5265 break;
5266 default:
5267 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
5268 return 0;
5269 }
5270 if (!buffer) {
5271 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no buffer");
5272 return 0;
5273 }
5274 return buffer;
5275 }
5276
validateHTMLImageElement(const char * functionName,HTMLImageElement * image,ExceptionState & exceptionState)5277 bool WebGLRenderingContextBase::validateHTMLImageElement(const char* functionName, HTMLImageElement* image, ExceptionState& exceptionState)
5278 {
5279 if (!image || !image->cachedImage()) {
5280 synthesizeGLError(GL_INVALID_VALUE, functionName, "no image");
5281 return false;
5282 }
5283 const KURL& url = image->cachedImage()->response().url();
5284 if (url.isNull() || url.isEmpty() || !url.isValid()) {
5285 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid image");
5286 return false;
5287 }
5288
5289 if (wouldTaintOrigin(image)) {
5290 exceptionState.throwSecurityError("The cross-origin image at " + url.elidedString() + " may not be loaded.");
5291 return false;
5292 }
5293 return true;
5294 }
5295
validateHTMLCanvasElement(const char * functionName,HTMLCanvasElement * canvas,ExceptionState & exceptionState)5296 bool WebGLRenderingContextBase::validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
5297 {
5298 if (!canvas || !canvas->buffer()) {
5299 synthesizeGLError(GL_INVALID_VALUE, functionName, "no canvas");
5300 return false;
5301 }
5302 if (wouldTaintOrigin(canvas)) {
5303 exceptionState.throwSecurityError("Tainted canvases may not be loaded.");
5304 return false;
5305 }
5306 return true;
5307 }
5308
validateHTMLVideoElement(const char * functionName,HTMLVideoElement * video,ExceptionState & exceptionState)5309 bool WebGLRenderingContextBase::validateHTMLVideoElement(const char* functionName, HTMLVideoElement* video, ExceptionState& exceptionState)
5310 {
5311 if (!video || !video->videoWidth() || !video->videoHeight()) {
5312 synthesizeGLError(GL_INVALID_VALUE, functionName, "no video");
5313 return false;
5314 }
5315
5316 if (wouldTaintOrigin(video)) {
5317 exceptionState.throwSecurityError("The video element contains cross-origin data, and may not be loaded.");
5318 return false;
5319 }
5320 return true;
5321 }
5322
validateDrawArrays(const char * functionName,GLenum mode,GLint first,GLsizei count)5323 bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GLenum mode, GLint first, GLsizei count)
5324 {
5325 if (isContextLost() || !validateDrawMode(functionName, mode))
5326 return false;
5327
5328 if (!validateStencilSettings(functionName))
5329 return false;
5330
5331 if (first < 0 || count < 0) {
5332 synthesizeGLError(GL_INVALID_VALUE, functionName, "first or count < 0");
5333 return false;
5334 }
5335
5336 if (!count) {
5337 markContextChanged(CanvasChanged);
5338 return false;
5339 }
5340
5341 if (!validateRenderingState(functionName)) {
5342 return false;
5343 }
5344
5345 const char* reason = "framebuffer incomplete";
5346 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
5347 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
5348 return false;
5349 }
5350
5351 return true;
5352 }
5353
validateDrawElements(const char * functionName,GLenum mode,GLsizei count,GLenum type,long long offset)5354 bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset)
5355 {
5356 if (isContextLost() || !validateDrawMode(functionName, mode))
5357 return false;
5358
5359 if (!validateStencilSettings(functionName))
5360 return false;
5361
5362 switch (type) {
5363 case GL_UNSIGNED_BYTE:
5364 case GL_UNSIGNED_SHORT:
5365 break;
5366 case GL_UNSIGNED_INT:
5367 if (extensionEnabled(OESElementIndexUintName))
5368 break;
5369 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type");
5370 return false;
5371 default:
5372 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type");
5373 return false;
5374 }
5375
5376 if (count < 0) {
5377 synthesizeGLError(GL_INVALID_VALUE, functionName, "count < 0");
5378 return false;
5379 }
5380 if (!validateValueFitNonNegInt32(functionName, "offset", offset))
5381 return false;
5382
5383 if (!count) {
5384 markContextChanged(CanvasChanged);
5385 return false;
5386 }
5387
5388 if (!m_boundVertexArrayObject->boundElementArrayBuffer()) {
5389 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
5390 return false;
5391 }
5392
5393 if (!validateRenderingState(functionName)) {
5394 return false;
5395 }
5396
5397 const char* reason = "framebuffer incomplete";
5398 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
5399 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
5400 return false;
5401 }
5402
5403 return true;
5404 }
5405
5406 // Helper function to validate draw*Instanced calls
validateDrawInstanced(const char * functionName,GLsizei primcount)5407 bool WebGLRenderingContextBase::validateDrawInstanced(const char* functionName, GLsizei primcount)
5408 {
5409 if (primcount < 0) {
5410 synthesizeGLError(GL_INVALID_VALUE, functionName, "primcount < 0");
5411 return false;
5412 }
5413
5414 return true;
5415 }
5416
vertexAttribfImpl(const char * functionName,GLuint index,GLsizei expectedSize,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3)5417 void WebGLRenderingContextBase::vertexAttribfImpl(const char* functionName, GLuint index, GLsizei expectedSize, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
5418 {
5419 if (isContextLost())
5420 return;
5421 if (index >= m_maxVertexAttribs) {
5422 synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range");
5423 return;
5424 }
5425 // In GL, we skip setting vertexAttrib0 values.
5426 switch (expectedSize) {
5427 case 1:
5428 webContext()->vertexAttrib1f(index, v0);
5429 break;
5430 case 2:
5431 webContext()->vertexAttrib2f(index, v0, v1);
5432 break;
5433 case 3:
5434 webContext()->vertexAttrib3f(index, v0, v1, v2);
5435 break;
5436 case 4:
5437 webContext()->vertexAttrib4f(index, v0, v1, v2, v3);
5438 break;
5439 }
5440 VertexAttribValue& attribValue = m_vertexAttribValue[index];
5441 attribValue.value[0] = v0;
5442 attribValue.value[1] = v1;
5443 attribValue.value[2] = v2;
5444 attribValue.value[3] = v3;
5445 }
5446
vertexAttribfvImpl(const char * functionName,GLuint index,Float32Array * v,GLsizei expectedSize)5447 void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, Float32Array* v, GLsizei expectedSize)
5448 {
5449 if (isContextLost())
5450 return;
5451 if (!v) {
5452 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5453 return;
5454 }
5455 vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize);
5456 }
5457
vertexAttribfvImpl(const char * functionName,GLuint index,GLfloat * v,GLsizei size,GLsizei expectedSize)5458 void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, GLfloat* v, GLsizei size, GLsizei expectedSize)
5459 {
5460 if (isContextLost())
5461 return;
5462 if (!v) {
5463 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5464 return;
5465 }
5466 if (size < expectedSize) {
5467 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size");
5468 return;
5469 }
5470 if (index >= m_maxVertexAttribs) {
5471 synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range");
5472 return;
5473 }
5474 // In GL, we skip setting vertexAttrib0 values.
5475 switch (expectedSize) {
5476 case 1:
5477 webContext()->vertexAttrib1fv(index, v);
5478 break;
5479 case 2:
5480 webContext()->vertexAttrib2fv(index, v);
5481 break;
5482 case 3:
5483 webContext()->vertexAttrib3fv(index, v);
5484 break;
5485 case 4:
5486 webContext()->vertexAttrib4fv(index, v);
5487 break;
5488 }
5489 VertexAttribValue& attribValue = m_vertexAttribValue[index];
5490 attribValue.initValue();
5491 for (int ii = 0; ii < expectedSize; ++ii)
5492 attribValue.value[ii] = v[ii];
5493 }
5494
dispatchContextLostEvent(Timer<WebGLRenderingContextBase> *)5495 void WebGLRenderingContextBase::dispatchContextLostEvent(Timer<WebGLRenderingContextBase>*)
5496 {
5497 RefPtrWillBeRawPtr<WebGLContextEvent> event = WebGLContextEvent::create(EventTypeNames::webglcontextlost, false, true, "");
5498 canvas()->dispatchEvent(event);
5499 m_restoreAllowed = event->defaultPrevented();
5500 if (m_restoreAllowed) {
5501 if (m_autoRecoveryMethod == Auto)
5502 m_restoreTimer.startOneShot(0, FROM_HERE);
5503 }
5504 }
5505
maybeRestoreContext(Timer<WebGLRenderingContextBase> *)5506 void WebGLRenderingContextBase::maybeRestoreContext(Timer<WebGLRenderingContextBase>*)
5507 {
5508 ASSERT(isContextLost());
5509
5510 // The rendering context is not restored unless the default behavior of the
5511 // webglcontextlost event was prevented earlier.
5512 //
5513 // Because of the way m_restoreTimer is set up for real vs. synthetic lost
5514 // context events, we don't have to worry about this test short-circuiting
5515 // the retry loop for real context lost events.
5516 if (!m_restoreAllowed)
5517 return;
5518
5519 LocalFrame* frame = canvas()->document().frame();
5520 if (!frame)
5521 return;
5522
5523 Settings* settings = frame->settings();
5524
5525 if (!frame->loader().client()->allowWebGL(settings && settings->webGLEnabled()))
5526 return;
5527
5528 // If the context was lost due to RealLostContext, we need to destroy the old DrawingBuffer before creating new DrawingBuffer to ensure resource budget enough.
5529 if (drawingBuffer()) {
5530 #if ENABLE(OILPAN)
5531 m_sharedWebGraphicsContext3D->dispose();
5532 #else
5533 m_drawingBuffer->beginDestruction();
5534 m_drawingBuffer.clear();
5535 #endif
5536 }
5537
5538 blink::WebGraphicsContext3D::Attributes attributes = m_requestedAttributes->attributes(canvas()->document().topDocument().url().string(), settings, version());
5539 OwnPtr<blink::WebGraphicsContext3D> context = adoptPtr(blink::Platform::current()->createOffscreenGraphicsContext3D(attributes, 0));
5540 RefPtr<DrawingBuffer> buffer;
5541 if (context) {
5542 // Construct a new drawing buffer with the new WebGraphicsContext3D.
5543 buffer = createDrawingBuffer(context.release());
5544 // If DrawingBuffer::create() fails to allocate a fbo, |drawingBuffer| is set to null.
5545 }
5546 if (!buffer) {
5547 if (m_contextLostMode == RealLostContext) {
5548 m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts, FROM_HERE);
5549 } else {
5550 // This likely shouldn't happen but is the best way to report it to the WebGL app.
5551 synthesizeGLError(GL_INVALID_OPERATION, "", "error restoring context");
5552 }
5553 return;
5554 }
5555
5556 #if ENABLE(OILPAN)
5557 if (m_sharedWebGraphicsContext3D)
5558 m_sharedWebGraphicsContext3D->update(buffer.release());
5559 else
5560 m_sharedWebGraphicsContext3D = WebGLSharedWebGraphicsContext3D::create(buffer.release());
5561 #else
5562 m_drawingBuffer = buffer.release();
5563 #endif
5564
5565 drawingBuffer()->bind();
5566 m_lostContextErrors.clear();
5567 m_contextLostMode = NotLostContext;
5568 m_autoRecoveryMethod = Manual;
5569 m_restoreAllowed = false;
5570 removeFromEvictedList(this);
5571
5572 setupFlags();
5573 initializeNewContext();
5574 markContextChanged(CanvasContextChanged);
5575 canvas()->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextrestored, false, true, ""));
5576 }
5577
ensureNotNull(const String & text) const5578 String WebGLRenderingContextBase::ensureNotNull(const String& text) const
5579 {
5580 if (text.isNull())
5581 return WTF::emptyString();
5582 return text;
5583 }
5584
LRUImageBufferCache(int capacity)5585 WebGLRenderingContextBase::LRUImageBufferCache::LRUImageBufferCache(int capacity)
5586 : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
5587 , m_capacity(capacity)
5588 {
5589 }
5590
imageBuffer(const IntSize & size)5591 ImageBuffer* WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer(const IntSize& size)
5592 {
5593 int i;
5594 for (i = 0; i < m_capacity; ++i) {
5595 ImageBuffer* buf = m_buffers[i].get();
5596 if (!buf)
5597 break;
5598 if (buf->size() != size)
5599 continue;
5600 bubbleToFront(i);
5601 return buf;
5602 }
5603
5604 OwnPtr<ImageBuffer> temp(ImageBuffer::create(size));
5605 if (!temp)
5606 return 0;
5607 i = std::min(m_capacity - 1, i);
5608 m_buffers[i] = temp.release();
5609
5610 ImageBuffer* buf = m_buffers[i].get();
5611 bubbleToFront(i);
5612 return buf;
5613 }
5614
bubbleToFront(int idx)5615 void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx)
5616 {
5617 for (int i = idx; i > 0; --i)
5618 m_buffers[i].swap(m_buffers[i-1]);
5619 }
5620
5621 namespace {
5622
GetErrorString(GLenum error)5623 String GetErrorString(GLenum error)
5624 {
5625 switch (error) {
5626 case GL_INVALID_ENUM:
5627 return "INVALID_ENUM";
5628 case GL_INVALID_VALUE:
5629 return "INVALID_VALUE";
5630 case GL_INVALID_OPERATION:
5631 return "INVALID_OPERATION";
5632 case GL_OUT_OF_MEMORY:
5633 return "OUT_OF_MEMORY";
5634 case GL_INVALID_FRAMEBUFFER_OPERATION:
5635 return "INVALID_FRAMEBUFFER_OPERATION";
5636 case GC3D_CONTEXT_LOST_WEBGL:
5637 return "CONTEXT_LOST_WEBGL";
5638 default:
5639 return String::format("WebGL ERROR(0x%04X)", error);
5640 }
5641 }
5642
5643 } // namespace anonymous
5644
synthesizeGLError(GLenum error,const char * functionName,const char * description,ConsoleDisplayPreference display)5645 void WebGLRenderingContextBase::synthesizeGLError(GLenum error, const char* functionName, const char* description, ConsoleDisplayPreference display)
5646 {
5647 String errorType = GetErrorString(error);
5648 if (m_synthesizedErrorsToConsole && display == DisplayInConsole) {
5649 String message = String("WebGL: ") + errorType + ": " + String(functionName) + ": " + String(description);
5650 printGLErrorToConsole(message);
5651 }
5652 if (!isContextLost())
5653 webContext()->synthesizeGLError(error);
5654 else {
5655 if (m_lostContextErrors.find(error) == WTF::kNotFound)
5656 m_lostContextErrors.append(error);
5657 }
5658 InspectorInstrumentation::didFireWebGLError(canvas(), errorType);
5659 }
5660
emitGLWarning(const char * functionName,const char * description)5661 void WebGLRenderingContextBase::emitGLWarning(const char* functionName, const char* description)
5662 {
5663 if (m_synthesizedErrorsToConsole) {
5664 String message = String("WebGL: ") + String(functionName) + ": " + String(description);
5665 printGLErrorToConsole(message);
5666 }
5667 InspectorInstrumentation::didFireWebGLWarning(canvas());
5668 }
5669
applyStencilTest()5670 void WebGLRenderingContextBase::applyStencilTest()
5671 {
5672 bool haveStencilBuffer = false;
5673
5674 if (m_framebufferBinding)
5675 haveStencilBuffer = m_framebufferBinding->hasStencilBuffer();
5676 else {
5677 RefPtrWillBeRawPtr<WebGLContextAttributes> attributes = getContextAttributes();
5678 haveStencilBuffer = attributes->stencil();
5679 }
5680 enableOrDisable(GL_STENCIL_TEST,
5681 m_stencilEnabled && haveStencilBuffer);
5682 }
5683
enableOrDisable(GLenum capability,bool enable)5684 void WebGLRenderingContextBase::enableOrDisable(GLenum capability, bool enable)
5685 {
5686 if (isContextLost())
5687 return;
5688 if (enable)
5689 webContext()->enable(capability);
5690 else
5691 webContext()->disable(capability);
5692 }
5693
clampedCanvasSize()5694 IntSize WebGLRenderingContextBase::clampedCanvasSize()
5695 {
5696 return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]),
5697 clamp(canvas()->height(), 1, m_maxViewportDims[1]));
5698 }
5699
maxDrawBuffers()5700 GLint WebGLRenderingContextBase::maxDrawBuffers()
5701 {
5702 if (isContextLost() || !extensionEnabled(WebGLDrawBuffersName))
5703 return 0;
5704 if (!m_maxDrawBuffers)
5705 webContext()->getIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers);
5706 if (!m_maxColorAttachments)
5707 webContext()->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
5708 // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
5709 return std::min(m_maxDrawBuffers, m_maxColorAttachments);
5710 }
5711
maxColorAttachments()5712 GLint WebGLRenderingContextBase::maxColorAttachments()
5713 {
5714 if (isContextLost() || !extensionEnabled(WebGLDrawBuffersName))
5715 return 0;
5716 if (!m_maxColorAttachments)
5717 webContext()->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
5718 return m_maxColorAttachments;
5719 }
5720
setBackDrawBuffer(GLenum buf)5721 void WebGLRenderingContextBase::setBackDrawBuffer(GLenum buf)
5722 {
5723 m_backDrawBuffer = buf;
5724 }
5725
restoreCurrentFramebuffer()5726 void WebGLRenderingContextBase::restoreCurrentFramebuffer()
5727 {
5728 bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding.get());
5729 }
5730
restoreCurrentTexture2D()5731 void WebGLRenderingContextBase::restoreCurrentTexture2D()
5732 {
5733 bindTexture(GL_TEXTURE_2D, m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get());
5734 }
5735
multisamplingChanged(bool enabled)5736 void WebGLRenderingContextBase::multisamplingChanged(bool enabled)
5737 {
5738 if (m_multisamplingAllowed != enabled) {
5739 m_multisamplingAllowed = enabled;
5740 forceLostContext(WebGLRenderingContextBase::SyntheticLostContext, WebGLRenderingContextBase::Auto);
5741 }
5742 }
5743
findNewMaxNonDefaultTextureUnit()5744 void WebGLRenderingContextBase::findNewMaxNonDefaultTextureUnit()
5745 {
5746 // Trace backwards from the current max to find the new max non-default texture unit
5747 int startIndex = m_onePlusMaxNonDefaultTextureUnit - 1;
5748 for (int i = startIndex; i >= 0; --i) {
5749 if (m_textureUnits[i].m_texture2DBinding
5750 || m_textureUnits[i].m_textureCubeMapBinding) {
5751 m_onePlusMaxNonDefaultTextureUnit = i + 1;
5752 return;
5753 }
5754 }
5755 m_onePlusMaxNonDefaultTextureUnit = 0;
5756 }
5757
trace(Visitor * visitor)5758 void WebGLRenderingContextBase::TextureUnitState::trace(Visitor* visitor)
5759 {
5760 visitor->trace(m_texture2DBinding);
5761 visitor->trace(m_textureCubeMapBinding);
5762 }
5763
trace(Visitor * visitor)5764 void WebGLRenderingContextBase::trace(Visitor* visitor)
5765 {
5766 #if ENABLE(OILPAN)
5767 visitor->trace(m_contextObjects);
5768 #endif
5769 visitor->trace(m_contextLostCallbackAdapter);
5770 visitor->trace(m_errorMessageCallbackAdapter);
5771 visitor->trace(m_boundArrayBuffer);
5772 visitor->trace(m_defaultVertexArrayObject);
5773 visitor->trace(m_boundVertexArrayObject);
5774 visitor->trace(m_vertexAttrib0Buffer);
5775 visitor->trace(m_currentProgram);
5776 visitor->trace(m_framebufferBinding);
5777 visitor->trace(m_renderbufferBinding);
5778 visitor->trace(m_textureUnits);
5779 visitor->trace(m_blackTexture2D);
5780 visitor->trace(m_blackTextureCubeMap);
5781 visitor->trace(m_requestedAttributes);
5782 visitor->trace(m_extensions);
5783 CanvasRenderingContext::trace(visitor);
5784 }
5785
5786 #if ENABLE(OILPAN)
sharedWebGraphicsContext3D() const5787 PassRefPtr<WebGLSharedWebGraphicsContext3D> WebGLRenderingContextBase::sharedWebGraphicsContext3D() const
5788 {
5789 return m_sharedWebGraphicsContext3D;
5790 }
5791
drawingBuffer() const5792 DrawingBuffer* WebGLRenderingContextBase::drawingBuffer() const
5793 {
5794 return m_sharedWebGraphicsContext3D ? m_sharedWebGraphicsContext3D->drawingBuffer() : 0;
5795 }
5796 #else
drawingBuffer() const5797 DrawingBuffer* WebGLRenderingContextBase::drawingBuffer() const
5798 {
5799 return m_drawingBuffer.get();
5800 }
5801 #endif
5802
5803 } // namespace blink
5804