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