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