Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: Source/core/html/canvas/WebGLRenderingContext.cpp

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

Powered by Google App Engine
This is Rietveld 408576698