1/*
2 * Copyright (C) 2015 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 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 INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if ENABLE(WEBGL)
29#include "WebGLRenderingContextBase.h"
30
31#include "ANGLEInstancedArrays.h"
32#include "CachedImage.h"
33#include "DOMWindow.h"
34#include "Document.h"
35#include "EXTBlendMinMax.h"
36#include "EXTFragDepth.h"
37#include "EXTShaderTextureLOD.h"
38#include "EXTTextureFilterAnisotropic.h"
39#include "EXTsRGB.h"
40#include "ExceptionCode.h"
41#include "Extensions3D.h"
42#include "Frame.h"
43#include "FrameLoader.h"
44#include "FrameLoaderClient.h"
45#include "FrameView.h"
46#include "GraphicsContext.h"
47#include "HTMLCanvasElement.h"
48#include "HTMLImageElement.h"
49#include "HTMLVideoElement.h"
50#include "ImageBuffer.h"
51#include "ImageData.h"
52#include "IntSize.h"
53#include "Logging.h"
54#include "MainFrame.h"
55#include "NotImplemented.h"
56#include "OESElementIndexUint.h"
57#include "OESStandardDerivatives.h"
58#include "OESTextureFloat.h"
59#include "OESTextureFloatLinear.h"
60#include "OESTextureHalfFloat.h"
61#include "OESTextureHalfFloatLinear.h"
62#include "OESVertexArrayObject.h"
63#include "Page.h"
64#include "RenderBox.h"
65#include "Settings.h"
66#include "WebGL1RenderingContext.h"
67#include "WebGL2RenderingContext.h"
68#include "WebGLActiveInfo.h"
69#include "WebGLBuffer.h"
70#include "WebGLCompressedTextureATC.h"
71#include "WebGLCompressedTexturePVRTC.h"
72#include "WebGLCompressedTextureS3TC.h"
73#include "WebGLContextAttributes.h"
74#include "WebGLContextEvent.h"
75#include "WebGLContextGroup.h"
76#include "WebGLDebugRendererInfo.h"
77#include "WebGLDebugShaders.h"
78#include "WebGLDepthTexture.h"
79#include "WebGLDrawBuffers.h"
80#include "WebGLFramebuffer.h"
81#include "WebGLLoseContext.h"
82#include "WebGLProgram.h"
83#include "WebGLRenderbuffer.h"
84#include "WebGLShader.h"
85#include "WebGLShaderPrecisionFormat.h"
86#include "WebGLTexture.h"
87#include "WebGLUniformLocation.h"
88
89#include <runtime/JSCInlines.h>
90#include <runtime/TypedArrayInlines.h>
91#include <runtime/Uint32Array.h>
92#include <wtf/StdLibExtras.h>
93#include <wtf/text/CString.h>
94#include <wtf/text/StringBuilder.h>
95
96namespace WebCore {
97
98const double secondsBetweenRestoreAttempts = 1.0;
99const int maxGLErrorsAllowedToConsole = 256;
100
101namespace {
102
103class ScopedDrawingBufferBinder {
104public:
105 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
106 : m_drawingBuffer(drawingBuffer)
107 , m_framebufferBinding(framebufferBinding)
108 {
109 // Commit DrawingBuffer if needed (e.g., for multisampling)
110 if (!m_framebufferBinding && m_drawingBuffer)
111 m_drawingBuffer->commit();
112 }
113
114 ~ScopedDrawingBufferBinder()
115 {
116 // Restore DrawingBuffer if needed
117 if (!m_framebufferBinding && m_drawingBuffer)
118 m_drawingBuffer->bind();
119 }
120
121private:
122 DrawingBuffer* m_drawingBuffer;
123 WebGLFramebuffer* m_framebufferBinding;
124};
125
126Platform3DObject objectOrZero(WebGLObject* object)
127{
128 return object ? object->object() : 0;
129}
130
131void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
132{
133 ASSERT(clippedStart && clippedRange);
134 if (start < 0) {
135 range += start;
136 start = 0;
137 }
138 GC3Dint end = start + range;
139 if (end > sourceRange)
140 range -= end - sourceRange;
141 *clippedStart = start;
142 *clippedRange = range;
143}
144
145// Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
146bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
147 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
148 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
149{
150 ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
151 clip1D(x, width, sourceWidth, clippedX, clippedWidth);
152 clip1D(y, height, sourceHeight, clippedY, clippedHeight);
153 return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
154}
155
156GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
157{
158 if (value < min)
159 value = min;
160 if (value > max)
161 value = max;
162 return value;
163}
164
165// Return true if a character belongs to the ASCII subset as defined in
166// GLSL ES 1.0 spec section 3.1.
167bool validateCharacter(unsigned char c)
168{
169 // Printing characters are valid except " $ ` @ \ ' DEL.
170 if (c >= 32 && c <= 126
171 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
172 return true;
173 // Horizontal tab, line feed, vertical tab, form feed, carriage return
174 // are also valid.
175 if (c >= 9 && c <= 13)
176 return true;
177 return false;
178}
179
180bool isPrefixReserved(const String& name)
181{
182 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
183 return true;
184 return false;
185}
186
187// Strips comments from shader text. This allows non-ASCII characters
188// to be used in comments without potentially breaking OpenGL
189// implementations not expecting characters outside the GLSL ES set.
190class StripComments {
191public:
192 StripComments(const String& str)
193 : m_parseState(BeginningOfLine)
194 , m_sourceString(str)
195 , m_length(str.length())
196 , m_position(0)
197 {
198 parse();
199 }
200
201 String result()
202 {
203 return m_builder.toString();
204 }
205
206private:
207 bool hasMoreCharacters() const
208 {
209 return (m_position < m_length);
210 }
211
212 void parse()
213 {
214 while (hasMoreCharacters()) {
215 process(current());
216 // process() might advance the position.
217 if (hasMoreCharacters())
218 advance();
219 }
220 }
221
222 void process(UChar);
223
224 bool peek(UChar& character) const
225 {
226 if (m_position + 1 >= m_length)
227 return false;
228 character = m_sourceString[m_position + 1];
229 return true;
230 }
231
232 UChar current() const
233 {
234 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
235 return m_sourceString[m_position];
236 }
237
238 void advance()
239 {
240 ++m_position;
241 }
242
243 bool isNewline(UChar character) const
244 {
245 // Don't attempt to canonicalize newline related characters.
246 return (character == '\n' || character == '\r');
247 }
248
249 void emit(UChar character)
250 {
251 m_builder.append(character);
252 }
253
254 enum ParseState {
255 // Have not seen an ASCII non-whitespace character yet on
256 // this line. Possible that we might see a preprocessor
257 // directive.
258 BeginningOfLine,
259
260 // Have seen at least one ASCII non-whitespace character
261 // on this line.
262 MiddleOfLine,
263
264 // Handling a preprocessor directive. Passes through all
265 // characters up to the end of the line. Disables comment
266 // processing.
267 InPreprocessorDirective,
268
269 // Handling a single-line comment. The comment text is
270 // replaced with a single space.
271 InSingleLineComment,
272
273 // Handling a multi-line comment. Newlines are passed
274 // through to preserve line numbers.
275 InMultiLineComment
276 };
277
278 ParseState m_parseState;
279 String m_sourceString;
280 unsigned m_length;
281 unsigned m_position;
282 StringBuilder m_builder;
283};
284
285void StripComments::process(UChar c)
286{
287 if (isNewline(c)) {
288 // No matter what state we are in, pass through newlines
289 // so we preserve line numbers.
290 emit(c);
291
292 if (m_parseState != InMultiLineComment)
293 m_parseState = BeginningOfLine;
294
295 return;
296 }
297
298 UChar temp = 0;
299 switch (m_parseState) {
300 case BeginningOfLine:
301 if (WTF::isASCIISpace(c)) {
302 emit(c);
303 break;
304 }
305
306 if (c == '#') {
307 m_parseState = InPreprocessorDirective;
308 emit(c);
309 break;
310 }
311
312 // Transition to normal state and re-handle character.
313 m_parseState = MiddleOfLine;
314 process(c);
315 break;
316
317 case MiddleOfLine:
318 if (c == '/' && peek(temp)) {
319 if (temp == '/') {
320 m_parseState = InSingleLineComment;
321 emit(' ');
322 advance();
323 break;
324 }
325
326 if (temp == '*') {
327 m_parseState = InMultiLineComment;
328 // Emit the comment start in case the user has
329 // an unclosed comment and we want to later
330 // signal an error.
331 emit('/');
332 emit('*');
333 advance();
334 break;
335 }
336 }
337
338 emit(c);
339 break;
340
341 case InPreprocessorDirective:
342 // No matter what the character is, just pass it
343 // through. Do not parse comments in this state. This
344 // might not be the right thing to do long term, but it
345 // should handle the #error preprocessor directive.
346 emit(c);
347 break;
348
349 case InSingleLineComment:
350 // The newline code at the top of this function takes care
351 // of resetting our state when we get out of the
352 // single-line comment. Swallow all other characters.
353 break;
354
355 case InMultiLineComment:
356 if (c == '*' && peek(temp) && temp == '/') {
357 emit('*');
358 emit('/');
359 m_parseState = MiddleOfLine;
360 advance();
361 break;
362 }
363
364 // Swallow all other characters. Unclear whether we may
365 // want or need to just emit a space per character to try
366 // to preserve column numbers for debugging purposes.
367 break;
368 }
369}
370} // namespace anonymous
371
372class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
373 WTF_MAKE_FAST_ALLOCATED;
374public:
375 explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb)
376 : m_context(cb) { }
377
378 virtual void onContextLost() override
379 {
380 m_context->forceLostContext(WebGLRenderingContextBase::RealLostContext);
381 }
382 virtual ~WebGLRenderingContextLostCallback() { }
383private:
384 WebGLRenderingContextBase* m_context;
385};
386
387class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
388 WTF_MAKE_FAST_ALLOCATED;
389public:
390 explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb)
391 : m_context(cb) { }
392
393 virtual void onErrorMessage(const String& message, GC3Dint) override
394 {
395 if (m_context->m_synthesizedErrorsToConsole)
396 m_context->printGLErrorToConsole(message);
397 }
398 virtual ~WebGLRenderingContextErrorMessageCallback() { }
399private:
400 WebGLRenderingContextBase* m_context;
401};
402
403std::unique_ptr<WebGLRenderingContextBase> WebGLRenderingContextBase::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs, const String& type)
404{
405 Document& document = canvas->document();
406 Frame* frame = document.frame();
407 if (!frame)
408 return nullptr;
409
410 // The FrameLoaderClient might block creation of a new WebGL context despite the page settings; in
411 // particular, if WebGL contexts were lost one or more times via the GL_ARB_robustness extension.
412 if (!frame->loader().client().allowWebGL(frame->settings().webGLEnabled())) {
413 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Web page was not allowed to create a WebGL context."));
414 return nullptr;
415 }
416
417 bool isPendingPolicyResolution = false;
418 Document& topDocument = document.topDocument();
419 Page* page = topDocument.page();
420 if (page && !topDocument.url().isLocalFile()) {
421 WebGLLoadPolicy policy = page->mainFrame().loader().client().webGLPolicyForURL(topDocument.url());
422
423 if (policy == WebGLBlockCreation) {
424 LOG(WebGL, "The policy for this URL (%s) is to block WebGL.", topDocument.url().host().utf8().data());
425 return nullptr;
426 }
427
428 if (policy == WebGLPendingCreation) {
429 LOG(WebGL, "WebGL policy is pending. May need to be resolved later.");
430 isPendingPolicyResolution = true;
431 }
432 }
433
434 GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
435
436 if (attributes.antialias) {
437 if (!frame->settings().openGLMultisamplingEnabled())
438 attributes.antialias = false;
439 }
440
441 attributes.noExtensions = true;
442 attributes.shareResources = false;
443 attributes.preferDiscreteGPU = true;
444
445 if (frame->settings().forceSoftwareWebGLRendering())
446 attributes.forceSoftwareRenderer = true;
447
448 if (page)
449 attributes.devicePixelRatio = page->deviceScaleFactor();
450
451 if (isPendingPolicyResolution) {
452 LOG(WebGL, "Create a WebGL context that looks real, but will require a policy resolution if used.");
453 std::unique_ptr<WebGLRenderingContextBase> renderingContext = nil;
454 if (type == "experimental-webgl2")
455 renderingContext = std::unique_ptr<WebGL2RenderingContext>(new WebGL2RenderingContext(canvas, attributes));
456 else
457 renderingContext = std::unique_ptr<WebGL1RenderingContext>(new WebGL1RenderingContext(canvas, attributes));
458 }
459
460 HostWindow* hostWindow = document.view()->root()->hostWindow();
461 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
462
463 if (!context || !context->makeContextCurrent()) {
464 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
465 return nullptr;
466 }
467
468 Extensions3D* extensions = context->getExtensions();
469 if (extensions->supports("GL_EXT_debug_marker"))
470 extensions->pushGroupMarkerEXT("WebGLRenderingContext");
471
472 std::unique_ptr<WebGLRenderingContextBase> renderingContext = nil;
473 if (type == "experimental-webgl2")
474 renderingContext = std::unique_ptr<WebGL2RenderingContext>(new WebGL2RenderingContext(canvas, context, attributes));
475 else
476 renderingContext = std::unique_ptr<WebGL1RenderingContext>(new WebGL1RenderingContext(canvas, context, attributes));
477 renderingContext->suspendIfNeeded();
478
479 return renderingContext;
480}
481
482WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, GraphicsContext3D::Attributes attributes)
483 : CanvasRenderingContext(passedCanvas)
484 , ActiveDOMObject(&passedCanvas->document())
485 , m_context(0)
486 , m_drawingBuffer(0)
487 , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
488 , m_restoreAllowed(false)
489 , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
490 , m_generatedImageCache(0)
491 , m_contextLost(false)
492 , m_contextLostMode(SyntheticLostContext)
493 , m_attributes(attributes)
494 , m_synthesizedErrorsToConsole(true)
495 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
496 , m_isPendingPolicyResolution(true)
497 , m_hasRequestedPolicyResolution(false)
498{
499}
500
501WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,GraphicsContext3D::Attributes attributes)
502 : CanvasRenderingContext(passedCanvas)
503 , ActiveDOMObject(&passedCanvas->document())
504 , m_context(context)
505 , m_drawingBuffer(0)
506 , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
507 , m_restoreAllowed(false)
508 , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
509 , m_generatedImageCache(4)
510 , m_contextLost(false)
511 , m_contextLostMode(SyntheticLostContext)
512 , m_attributes(attributes)
513 , m_synthesizedErrorsToConsole(true)
514 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
515 , m_isPendingPolicyResolution(false)
516 , m_hasRequestedPolicyResolution(false)
517{
518 ASSERT(m_context);
519 m_contextGroup = WebGLContextGroup::create();
520 m_contextGroup->addContext(this);
521
522 m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
523 m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
524
525 if (m_drawingBuffer)
526 m_drawingBuffer->bind();
527
528 setupFlags();
529 initializeNewContext();
530}
531
532void WebGLRenderingContextBase::initializeNewContext()
533{
534 ASSERT(!m_contextLost);
535 m_needsUpdate = true;
536 m_markedCanvasDirty = false;
537 m_activeTextureUnit = 0;
538 m_packAlignment = 4;
539 m_unpackAlignment = 4;
540 m_unpackFlipY = false;
541 m_unpackPremultiplyAlpha = false;
542 m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
543 m_boundArrayBuffer = 0;
544 m_currentProgram = 0;
545 m_framebufferBinding = 0;
546 m_renderbufferBinding = 0;
547 m_depthMask = true;
548 m_stencilEnabled = false;
549 m_stencilMask = 0xFFFFFFFF;
550 m_stencilMaskBack = 0xFFFFFFFF;
551 m_stencilFuncRef = 0;
552 m_stencilFuncRefBack = 0;
553 m_stencilFuncMask = 0xFFFFFFFF;
554 m_stencilFuncMaskBack = 0xFFFFFFFF;
555 m_layerCleared = false;
556 m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
557
558 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
559 m_scissorEnabled = false;
560 m_clearDepth = 1;
561 m_clearStencil = 0;
562 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
563
564 GC3Dint numCombinedTextureImageUnits = 0;
565 m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
566 m_textureUnits.clear();
567 m_textureUnits.resize(numCombinedTextureImageUnits);
568
569 GC3Dint numVertexAttribs = 0;
570 m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
571 m_maxVertexAttribs = numVertexAttribs;
572
573 m_maxTextureSize = 0;
574 m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
575 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
576 m_maxCubeMapTextureSize = 0;
577 m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
578 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
579 m_maxRenderbufferSize = 0;
580 m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
581
582 // These two values from EXT_draw_buffers are lazily queried.
583 m_maxDrawBuffers = 0;
584 m_maxColorAttachments = 0;
585
586 m_backDrawBuffer = GraphicsContext3D::BACK;
587 m_drawBuffersWebGLRequirementsChecked = false;
588 m_drawBuffersSupported = false;
589
590 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
591 addContextObject(m_defaultVertexArrayObject.get());
592 m_boundVertexArrayObject = m_defaultVertexArrayObject;
593
594 m_vertexAttribValue.resize(m_maxVertexAttribs);
595
596 if (!isGLES2NPOTStrict())
597 createFallbackBlackTextures1x1();
598 if (!isGLES2Compliant())
599 initVertexAttrib0();
600
601 IntSize canvasSize = clampedCanvasSize();
602 if (m_drawingBuffer)
603 m_drawingBuffer->reset(canvasSize);
604
605 m_context->reshape(canvasSize.width(), canvasSize.height());
606 m_context->viewport(0, 0, canvasSize.width(), canvasSize.height());
607 m_context->scissor(0, 0, canvasSize.width(), canvasSize.height());
608
609 m_context->setContextLostCallback(std::make_unique<WebGLRenderingContextLostCallback>(this));
610 m_context->setErrorMessageCallback(std::make_unique<WebGLRenderingContextErrorMessageCallback>(this));
611}
612
613void WebGLRenderingContextBase::setupFlags()
614{
615 ASSERT(m_context);
616
617 if (Page* page = canvas()->document().page())
618 m_synthesizedErrorsToConsole = page->settings().webGLErrorsToConsoleEnabled();
619
620 m_isGLES2Compliant = m_context->isGLES2Compliant();
621 m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
622 m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
623 if (m_isGLES2Compliant) {
624 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
625 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
626 } else {
627 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
628 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
629 }
630 m_isRobustnessEXTSupported = m_context->getExtensions()->isEnabled("GL_EXT_robustness");
631}
632
633bool WebGLRenderingContextBase::allowPrivilegedExtensions() const
634{
635 if (Page* page = canvas()->document().page())
636 return page->settings().privilegedWebGLExtensionsEnabled();
637 return false;
638}
639
640void WebGLRenderingContextBase::addCompressedTextureFormat(GC3Denum format)
641{
642 if (!m_compressedTextureFormats.contains(format))
643 m_compressedTextureFormats.append(format);
644}
645
646WebGLRenderingContextBase::~WebGLRenderingContextBase()
647{
648 // Remove all references to WebGLObjects so if they are the last reference
649 // they will be freed before the last context is removed from the context group.
650 m_boundArrayBuffer = nullptr;
651 m_defaultVertexArrayObject = nullptr;
652 m_boundVertexArrayObject = nullptr;
653 m_vertexAttrib0Buffer = nullptr;
654 m_currentProgram = nullptr;
655 m_framebufferBinding = nullptr;
656 m_renderbufferBinding = nullptr;
657
658 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
659 m_textureUnits[i].texture2DBinding = nullptr;
660 m_textureUnits[i].textureCubeMapBinding = nullptr;
661 }
662
663 m_blackTexture2D = nullptr;
664 m_blackTextureCubeMap = nullptr;
665
666 if (!m_isPendingPolicyResolution) {
667 detachAndRemoveAllObjects();
668 destroyGraphicsContext3D();
669 m_contextGroup->removeContext(this);
670 }
671}
672
673void WebGLRenderingContextBase::destroyGraphicsContext3D()
674{
675 if (m_isPendingPolicyResolution)
676 return;
677
678 // The drawing buffer holds a context reference. It must also be destroyed
679 // in order for the context to be released.
680 if (m_drawingBuffer)
681 m_drawingBuffer.clear();
682
683 if (m_context) {
684 m_context->setContextLostCallback(nullptr);
685 m_context->setErrorMessageCallback(nullptr);
686 m_context.clear();
687 }
688}
689
690void WebGLRenderingContextBase::markContextChanged()
691{
692 if (m_framebufferBinding)
693 return;
694
695 m_context->markContextChanged();
696
697 if (m_drawingBuffer)
698 m_drawingBuffer->markContentsChanged();
699
700 m_layerCleared = false;
701 RenderBox* renderBox = canvas()->renderBox();
702 if (isAccelerated() && renderBox && renderBox->hasAcceleratedCompositing()) {
703 m_markedCanvasDirty = true;
704 canvas()->clearCopiedImage();
705 renderBox->contentChanged(CanvasChanged);
706 } else {
707 if (!m_markedCanvasDirty) {
708 m_markedCanvasDirty = true;
709 canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
710 }
711 }
712}
713
714bool WebGLRenderingContextBase::clearIfComposited(GC3Dbitfield mask)
715{
716 if (isContextLostOrPending())
717 return false;
718
719 if (!m_context->layerComposited() || m_layerCleared
720 || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
721 return false;
722
723 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
724
725 // Determine if it's possible to combine the clear the user asked for and this clear.
726 bool combinedClear = mask && !m_scissorEnabled;
727
728 m_context->disable(GraphicsContext3D::SCISSOR_TEST);
729 if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT)) {
730 m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
731 m_colorMask[1] ? m_clearColor[1] : 0,
732 m_colorMask[2] ? m_clearColor[2] : 0,
733 m_colorMask[3] ? m_clearColor[3] : 0);
734 } else
735 m_context->clearColor(0, 0, 0, 0);
736 m_context->colorMask(true, true, true, true);
737 GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
738 if (contextAttributes->depth()) {
739 if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
740 m_context->clearDepth(1.0f);
741 clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
742 m_context->depthMask(true);
743 }
744 if (contextAttributes->stencil()) {
745 if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
746 m_context->clearStencil(m_clearStencil & m_stencilMask);
747 else
748 m_context->clearStencil(0);
749 clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
750 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
751 }
752 if (m_drawingBuffer)
753 m_drawingBuffer->clearFramebuffers(clearMask);
754 else {
755 if (m_framebufferBinding)
756 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
757 m_context->clear(clearMask);
758 }
759
760 restoreStateAfterClear();
761 if (m_framebufferBinding)
762 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
763 m_layerCleared = true;
764
765 return combinedClear;
766}
767
768void WebGLRenderingContextBase::restoreStateAfterClear()
769{
770 // Restore the state that the context set.
771 if (m_scissorEnabled)
772 m_context->enable(GraphicsContext3D::SCISSOR_TEST);
773 m_context->clearColor(m_clearColor[0], m_clearColor[1],
774 m_clearColor[2], m_clearColor[3]);
775 m_context->colorMask(m_colorMask[0], m_colorMask[1],
776 m_colorMask[2], m_colorMask[3]);
777 m_context->clearDepth(m_clearDepth);
778 m_context->clearStencil(m_clearStencil);
779 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
780 m_context->depthMask(m_depthMask);
781}
782
783void WebGLRenderingContextBase::markLayerComposited()
784{
785 if (isContextLostOrPending())
786 return;
787 m_context->markLayerComposited();
788}
789
790void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
791{
792 if (isContextLostOrPending())
793 return;
794
795 if (canvas()->document().printing())
796 canvas()->clearPresentationCopy();
797
798 // Until the canvas is written to by the application, the clear that
799 // happened after it was composited should be ignored by the compositor.
800 if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
801 m_context->paintCompositedResultsToCanvas(canvas()->buffer());
802
803 canvas()->makePresentationCopy();
804 } else
805 canvas()->clearPresentationCopy();
806 clearIfComposited();
807
808 if (!m_markedCanvasDirty && !m_layerCleared)
809 return;
810
811 canvas()->clearCopiedImage();
812 m_markedCanvasDirty = false;
813
814 if (m_drawingBuffer)
815 m_drawingBuffer->commit();
816 m_context->paintRenderingResultsToCanvas(canvas()->buffer(), m_drawingBuffer.get());
817
818 if (m_drawingBuffer) {
819 if (m_framebufferBinding)
820 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
821 else
822 m_drawingBuffer->bind();
823 }
824}
825
826PassRefPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData()
827{
828 if (isContextLostOrPending())
829 return nullptr;
830 clearIfComposited();
831 if (m_drawingBuffer)
832 m_drawingBuffer->commit();
833 RefPtr<ImageData> imageData = m_context->paintRenderingResultsToImageData(m_drawingBuffer.get());
834
835 if (m_drawingBuffer) {
836 if (m_framebufferBinding)
837 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
838 else
839 m_drawingBuffer->bind();
840 }
841
842 return imageData;
843}
844
845void WebGLRenderingContextBase::reshape(int width, int height)
846{
847 if (isContextLostOrPending())
848 return;
849
850 // This is an approximation because at WebGLRenderingContext level we don't
851 // know if the underlying FBO uses textures or renderbuffers.
852 GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
853 // Limit drawing buffer size to 4k to avoid memory exhaustion.
854 const int sizeUpperLimit = 4096;
855 maxSize = std::min(maxSize, sizeUpperLimit);
856 GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
857 GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
858 width = clamp(width, 1, maxWidth);
859 height = clamp(height, 1, maxHeight);
860
861 if (m_needsUpdate) {
862 RenderBox* renderBox = canvas()->renderBox();
863 if (renderBox && renderBox->hasAcceleratedCompositing())
864 renderBox->contentChanged(CanvasChanged);
865 m_needsUpdate = false;
866 }
867
868 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
869 // clear (and this matches what reshape will do).
870 if (m_drawingBuffer) {
871 m_drawingBuffer->reset(IntSize(width, height));
872 restoreStateAfterClear();
873 } else
874 m_context->reshape(width, height);
875
876 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].texture2DBinding.get()));
877 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
878 if (m_framebufferBinding)
879 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
880}
881
882int WebGLRenderingContextBase::drawingBufferWidth() const
883{
884 if (m_drawingBuffer)
885 return m_drawingBuffer->size().width();
886
887 return m_context->getInternalFramebufferSize().width();
888}
889
890int WebGLRenderingContextBase::drawingBufferHeight() const
891{
892 if (m_drawingBuffer)
893 return m_drawingBuffer->size().height();
894
895 return m_context->getInternalFramebufferSize().height();
896}
897
898unsigned WebGLRenderingContextBase::sizeInBytes(GC3Denum type)
899{
900 switch (type) {
901 case GraphicsContext3D::BYTE:
902 return sizeof(GC3Dbyte);
903 case GraphicsContext3D::UNSIGNED_BYTE:
904 return sizeof(GC3Dubyte);
905 case GraphicsContext3D::SHORT:
906 return sizeof(GC3Dshort);
907 case GraphicsContext3D::UNSIGNED_SHORT:
908 return sizeof(GC3Dushort);
909 case GraphicsContext3D::INT:
910 return sizeof(GC3Dint);
911 case GraphicsContext3D::UNSIGNED_INT:
912 return sizeof(GC3Duint);
913 case GraphicsContext3D::FLOAT:
914 return sizeof(GC3Dfloat);
915 }
916 ASSERT_NOT_REACHED();
917 return 0;
918}
919
920void WebGLRenderingContextBase::activeTexture(GC3Denum texture, ExceptionCode& ec)
921{
922 UNUSED_PARAM(ec);
923 if (isContextLostOrPending())
924 return;
925 if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
926 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
927 return;
928 }
929 m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
930 m_context->activeTexture(texture);
931
932 if (m_drawingBuffer)
933 m_drawingBuffer->setActiveTextureUnit(texture);
934}
935
936void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
937{
938 UNUSED_PARAM(ec);
939 if (isContextLostOrPending() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
940 return;
941 if (!program->attachShader(shader)) {
942 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
943 return;
944 }
945 m_context->attachShader(objectOrZero(program), objectOrZero(shader));
946 shader->onAttached();
947}
948
949void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
950{
951 UNUSED_PARAM(ec);
952 if (isContextLostOrPending() || !validateWebGLObject("bindAttribLocation", program))
953 return;
954 if (!validateLocationLength("bindAttribLocation", name))
955 return;
956 if (!validateString("bindAttribLocation", name))
957 return;
958 if (isPrefixReserved(name)) {
959 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
960 return;
961 }
962 if (index >= m_maxVertexAttribs) {
963 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
964 return;
965 }
966 m_context->bindAttribLocation(objectOrZero(program), index, name);
967}
968
969bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
970{
971 deleted = false;
972 if (isContextLostOrPending())
973 return false;
974 if (object) {
975 if (!object->validate(contextGroup(), this)) {
976 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
977 return false;
978 }
979 deleted = !object->object();
980 }
981 return true;
982}
983
984void WebGLRenderingContextBase::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
985{
986 UNUSED_PARAM(ec);
987 bool deleted;
988 if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
989 return;
990 if (deleted)
991 buffer = 0;
992 if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
993 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
994 return;
995 }
996 if (target == GraphicsContext3D::ARRAY_BUFFER)
997 m_boundArrayBuffer = buffer;
998 else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
999 m_boundVertexArrayObject->setElementArrayBuffer(buffer);
1000 else {
1001 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
1002 return;
1003 }
1004
1005 m_context->bindBuffer(target, objectOrZero(buffer));
1006 if (buffer)
1007 buffer->setTarget(target);
1008}
1009
1010void WebGLRenderingContextBase::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
1011{
1012 UNUSED_PARAM(ec);
1013 bool deleted;
1014 if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
1015 return;
1016 if (deleted)
1017 buffer = 0;
1018 if (target != GraphicsContext3D::FRAMEBUFFER) {
1019 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
1020 return;
1021 }
1022 m_framebufferBinding = buffer;
1023 if (m_drawingBuffer)
1024 m_drawingBuffer->setFramebufferBinding(objectOrZero(m_framebufferBinding.get()));
1025 if (!m_framebufferBinding && m_drawingBuffer) {
1026 // Instead of binding fb 0, bind the drawing buffer.
1027 m_drawingBuffer->bind();
1028 } else
1029 m_context->bindFramebuffer(target, objectOrZero(buffer));
1030 if (buffer)
1031 buffer->setHasEverBeenBound();
1032 applyStencilTest();
1033}
1034
1035void WebGLRenderingContextBase::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
1036{
1037 UNUSED_PARAM(ec);
1038 bool deleted;
1039 if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
1040 return;
1041 if (deleted)
1042 renderBuffer = 0;
1043 if (target != GraphicsContext3D::RENDERBUFFER) {
1044 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
1045 return;
1046 }
1047 m_renderbufferBinding = renderBuffer;
1048 m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
1049 if (renderBuffer)
1050 renderBuffer->setHasEverBeenBound();
1051}
1052
1053void WebGLRenderingContextBase::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
1054{
1055 UNUSED_PARAM(ec);
1056 bool deleted;
1057 if (!checkObjectToBeBound("bindTexture", texture, deleted))
1058 return;
1059 if (deleted)
1060 texture = 0;
1061 if (texture && texture->getTarget() && texture->getTarget() != target) {
1062 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
1063 return;
1064 }
1065 GC3Dint maxLevel = 0;
1066 if (target == GraphicsContext3D::TEXTURE_2D) {
1067 m_textureUnits[m_activeTextureUnit].texture2DBinding = texture;
1068 maxLevel = m_maxTextureLevel;
1069
1070 if (m_drawingBuffer && !m_activeTextureUnit)
1071 m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
1072
1073 } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
1074 m_textureUnits[m_activeTextureUnit].textureCubeMapBinding = texture;
1075 maxLevel = m_maxCubeMapTextureLevel;
1076 } else {
1077 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
1078 return;
1079 }
1080 m_context->bindTexture(target, objectOrZero(texture));
1081 if (texture)
1082 texture->setTarget(target, maxLevel);
1083
1084 // Note: previously we used to automatically set the TEXTURE_WRAP_R
1085 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
1086 // ES 2.0 doesn't expose this flag (a bug in the specification) and
1087 // otherwise the application has no control over the seams in this
1088 // dimension. However, it appears that supporting this properly on all
1089 // platforms is fairly involved (will require a HashMap from texture ID
1090 // in all ports), and we have not had any complaints, so the logic has
1091 // been removed.
1092}
1093
1094void WebGLRenderingContextBase::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
1095{
1096 if (isContextLostOrPending())
1097 return;
1098 m_context->blendColor(red, green, blue, alpha);
1099}
1100
1101void WebGLRenderingContextBase::blendEquation(GC3Denum mode)
1102{
1103 if (isContextLostOrPending() || !validateBlendEquation("blendEquation", mode))
1104 return;
1105 m_context->blendEquation(mode);
1106}
1107
1108void WebGLRenderingContextBase::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
1109{
1110 if (isContextLostOrPending() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
1111 return;
1112 m_context->blendEquationSeparate(modeRGB, modeAlpha);
1113}
1114
1115
1116void WebGLRenderingContextBase::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
1117{
1118 if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1119 return;
1120 m_context->blendFunc(sfactor, dfactor);
1121}
1122
1123void WebGLRenderingContextBase::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1124{
1125 // Note: Alpha does not have the same restrictions as RGB.
1126 if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1127 return;
1128 m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1129}
1130
1131void WebGLRenderingContextBase::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode& ec)
1132{
1133 UNUSED_PARAM(ec);
1134 if (isContextLostOrPending())
1135 return;
1136 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1137 if (!buffer)
1138 return;
1139 if (size < 0) {
1140 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1141 return;
1142 }
1143 if (!size) {
1144 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size == 0");
1145 return;
1146 }
1147 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1148 if (!buffer->associateBufferData(static_cast<GC3Dsizeiptr>(size))) {
1149 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1150 return;
1151 }
1152 }
1153
1154 m_context->moveErrorsToSyntheticErrorList();
1155 m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
1156 if (m_context->moveErrorsToSyntheticErrorList()) {
1157 // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1158 buffer->disassociateBufferData();
1159 }
1160}
1161
1162void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
1163{
1164 UNUSED_PARAM(ec);
1165 if (isContextLostOrPending())
1166 return;
1167 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1168 if (!buffer)
1169 return;
1170 if (!data) {
1171 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1172 return;
1173 }
1174 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1175 if (!buffer->associateBufferData(data)) {
1176 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1177 return;
1178 }
1179 }
1180
1181 m_context->moveErrorsToSyntheticErrorList();
1182 m_context->bufferData(target, data->byteLength(), data->data(), usage);
1183 if (m_context->moveErrorsToSyntheticErrorList()) {
1184 // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1185 buffer->disassociateBufferData();
1186 }
1187}
1188
1189void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
1190{
1191 UNUSED_PARAM(ec);
1192 if (isContextLostOrPending())
1193 return;
1194 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1195 if (!buffer)
1196 return;
1197 if (!data) {
1198 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1199 return;
1200 }
1201 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1202 if (!buffer->associateBufferData(data)) {
1203 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1204 return;
1205 }
1206 }
1207
1208 m_context->moveErrorsToSyntheticErrorList();
1209 m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
1210 if (m_context->moveErrorsToSyntheticErrorList()) {
1211 // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1212 buffer->disassociateBufferData();
1213 }
1214}
1215
1216void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode& ec)
1217{
1218 UNUSED_PARAM(ec);
1219 if (isContextLostOrPending())
1220 return;
1221 WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1222 if (!buffer)
1223 return;
1224 if (offset < 0) {
1225 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1226 return;
1227 }
1228 if (!data)
1229 return;
1230 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1231 if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1232 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1233 return;
1234 }
1235 }
1236
1237 m_context->moveErrorsToSyntheticErrorList();
1238 m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
1239 if (m_context->moveErrorsToSyntheticErrorList()) {
1240 // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1241 buffer->disassociateBufferData();
1242 }
1243}
1244
1245void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode& ec)
1246{
1247 UNUSED_PARAM(ec);
1248 if (isContextLostOrPending())
1249 return;
1250 WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1251 if (!buffer)
1252 return;
1253 if (offset < 0) {
1254 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1255 return;
1256 }
1257 if (!data)
1258 return;
1259 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1260 if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1261 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1262 return;
1263 }
1264 }
1265
1266 m_context->moveErrorsToSyntheticErrorList();
1267 m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->baseAddress());
1268 if (m_context->moveErrorsToSyntheticErrorList()) {
1269 // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1270 buffer->disassociateBufferData();
1271 }
1272}
1273
1274GC3Denum WebGLRenderingContextBase::checkFramebufferStatus(GC3Denum target)
1275{
1276 if (isContextLostOrPending())
1277 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1278 if (target != GraphicsContext3D::FRAMEBUFFER) {
1279 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1280 return 0;
1281 }
1282 if (!m_framebufferBinding || !m_framebufferBinding->object())
1283 return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1284 const char* reason = "framebuffer incomplete";
1285 GC3Denum result = m_framebufferBinding->checkStatus(&reason);
1286 if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
1287 printGLWarningToConsole("checkFramebufferStatus", reason);
1288 return result;
1289 }
1290 result = m_context->checkFramebufferStatus(target);
1291 return result;
1292}
1293
1294void WebGLRenderingContextBase::clear(GC3Dbitfield mask)
1295{
1296 if (isContextLostOrPending())
1297 return;
1298 if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1299 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
1300 return;
1301 }
1302 const char* reason = "framebuffer incomplete";
1303 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1304 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
1305 return;
1306 }
1307 if (!clearIfComposited(mask))
1308 m_context->clear(mask);
1309 markContextChanged();
1310}
1311
1312void WebGLRenderingContextBase::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1313{
1314 if (isContextLostOrPending())
1315 return;
1316 if (std::isnan(r))
1317 r = 0;
1318 if (std::isnan(g))
1319 g = 0;
1320 if (std::isnan(b))
1321 b = 0;
1322 if (std::isnan(a))
1323 a = 1;
1324 m_clearColor[0] = r;
1325 m_clearColor[1] = g;
1326 m_clearColor[2] = b;
1327 m_clearColor[3] = a;
1328 m_context->clearColor(r, g, b, a);
1329}
1330
1331void WebGLRenderingContextBase::clearDepth(GC3Dfloat depth)
1332{
1333 if (isContextLostOrPending())
1334 return;
1335 m_clearDepth = depth;
1336 m_context->clearDepth(depth);
1337}
1338
1339void WebGLRenderingContextBase::clearStencil(GC3Dint s)
1340{
1341 if (isContextLostOrPending())
1342 return;
1343 m_clearStencil = s;
1344 m_context->clearStencil(s);
1345}
1346
1347void WebGLRenderingContextBase::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1348{
1349 if (isContextLostOrPending())
1350 return;
1351 m_colorMask[0] = red;
1352 m_colorMask[1] = green;
1353 m_colorMask[2] = blue;
1354 m_colorMask[3] = alpha;
1355 m_context->colorMask(red, green, blue, alpha);
1356}
1357
1358void WebGLRenderingContextBase::compileShader(WebGLShader* shader, ExceptionCode& ec)
1359{
1360 UNUSED_PARAM(ec);
1361 if (isContextLostOrPending() || !validateWebGLObject("compileShader", shader))
1362 return;
1363 m_context->compileShader(objectOrZero(shader));
1364 GC3Dint value;
1365 m_context->getShaderiv(objectOrZero(shader), GraphicsContext3D::COMPILE_STATUS, &value);
1366 shader->setValid(value);
1367}
1368
1369void WebGLRenderingContextBase::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
1370 GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
1371{
1372 if (isContextLostOrPending())
1373 return;
1374 if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1375 return;
1376
1377 if (!validateCompressedTexFormat(internalformat)) {
1378 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1379 return;
1380 }
1381 if (border) {
1382 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1383 return;
1384 }
1385 if (!validateCompressedTexDimensions("compressedTexImage2D", target, level, width, height, internalformat))
1386 return;
1387 if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1388 return;
1389
1390 WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1391 if (!tex)
1392 return;
1393 if (!isGLES2NPOTStrict()) {
1394 if (level && WebGLTexture::isNPOT(width, height)) {
1395 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1396 return;
1397 }
1398 }
1399 m_context->moveErrorsToSyntheticErrorList();
1400 m_context->compressedTexImage2D(target, level, internalformat, width, height,
1401 border, data->byteLength(), data->baseAddress());
1402 if (m_context->moveErrorsToSyntheticErrorList()) {
1403 // The compressedTexImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
1404 tex->markInvalid(target, level);
1405 return;
1406 }
1407
1408 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1409 tex->setCompressed();
1410}
1411
1412void WebGLRenderingContextBase::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
1413 GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
1414{
1415 if (isContextLostOrPending())
1416 return;
1417 if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1418 return;
1419 if (!validateCompressedTexFormat(format)) {
1420 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1421 return;
1422 }
1423 if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1424 return;
1425
1426 WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1427 if (!tex)
1428 return;
1429
1430 if (format != tex->getInternalFormat(target, level)) {
1431 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1432 return;
1433 }
1434
1435 if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1436 return;
1437
1438 graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1439 width, height, format, data->byteLength(), data->baseAddress());
1440 tex->setCompressed();
1441}
1442
1443bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GC3Denum format)
1444{
1445 if (GraphicsContext3D::getClearBitsByFormat(format) & (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1446 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1447 return false;
1448 }
1449 return true;
1450}
1451
1452void WebGLRenderingContextBase::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1453{
1454 if (isContextLostOrPending())
1455 return;
1456 if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1457 return;
1458 if (!validateSettableTexFormat("copyTexImage2D", internalformat))
1459 return;
1460 WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
1461 if (!tex)
1462 return;
1463 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1464 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
1465 return;
1466 }
1467 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1468 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
1469 return;
1470 }
1471 const char* reason = "framebuffer incomplete";
1472 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1473 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason);
1474 return;
1475 }
1476 clearIfComposited();
1477 if (isResourceSafe()) {
1478 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1479 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1480 } else {
1481 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1482 GC3Dint clippedX, clippedY;
1483 GC3Dsizei clippedWidth, clippedHeight;
1484 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1485 m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1486 internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1487 if (clippedWidth > 0 && clippedHeight > 0) {
1488 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1489 clippedX, clippedY, clippedWidth, clippedHeight);
1490 }
1491 } else
1492 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1493 }
1494 // FIXME: if the framebuffer is not complete, none of the below should be executed.
1495 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1496}
1497
1498void WebGLRenderingContextBase::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1499{
1500 if (isContextLostOrPending())
1501 return;
1502 if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1503 return;
1504 WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1505 if (!tex)
1506 return;
1507 if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1508 return;
1509 // Before checking if it is in the range, check if overflow happens first.
1510 if (xoffset + width < 0 || yoffset + height < 0) {
1511 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
1512 return;
1513 }
1514 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1515 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1516 return;
1517 }
1518 GC3Denum internalformat = tex->getInternalFormat(target, level);
1519 if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
1520 return;
1521 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1522 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1523 return;
1524 }
1525 const char* reason = "framebuffer incomplete";
1526 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1527 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1528 return;
1529 }
1530 clearIfComposited();
1531 if (isResourceSafe()) {
1532 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1533 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1534 } else {
1535 GC3Dint clippedX, clippedY;
1536 GC3Dsizei clippedWidth, clippedHeight;
1537 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1538 GC3Denum format = tex->getInternalFormat(target, level);
1539 GC3Denum type = tex->getType(target, level);
1540 std::unique_ptr<unsigned char[]> zero;
1541 if (width && height) {
1542 unsigned size;
1543 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1544 if (error != GraphicsContext3D::NO_ERROR) {
1545 synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1546 return;
1547 }
1548 zero = std::make_unique<unsigned char[]>(size);
1549 if (!zero) {
1550 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1551 return;
1552 }
1553 memset(zero.get(), 0, size);
1554 }
1555 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1556 if (clippedWidth > 0 && clippedHeight > 0) {
1557 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1558 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1559 clippedX, clippedY, clippedWidth, clippedHeight);
1560 }
1561 } else {
1562 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1563 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1564 }
1565 }
1566}
1567
1568PassRefPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer()
1569{
1570 if (isContextLostOrPending())
1571 return nullptr;
1572 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1573 addSharedObject(o.get());
1574 return o;
1575}
1576
1577PassRefPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer()
1578{
1579 if (isContextLostOrPending())
1580 return nullptr;
1581 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1582 addContextObject(o.get());
1583 return o;
1584}
1585
1586PassRefPtr<WebGLTexture> WebGLRenderingContextBase::createTexture()
1587{
1588 if (isContextLostOrPending())
1589 return nullptr;
1590 RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1591 addSharedObject(o.get());
1592 return o;
1593}
1594
1595PassRefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
1596{
1597 if (isContextLostOrPending())
1598 return nullptr;
1599 RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1600 addSharedObject(o.get());
1601 return o;
1602}
1603
1604PassRefPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer()
1605{
1606 if (isContextLostOrPending())
1607 return nullptr;
1608 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1609 addSharedObject(o.get());
1610 return o;
1611}
1612
1613PassRefPtr<WebGLShader> WebGLRenderingContextBase::createShader(GC3Denum type, ExceptionCode& ec)
1614{
1615 UNUSED_PARAM(ec);
1616 if (isContextLostOrPending())
1617 return nullptr;
1618 if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1619 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1620 return nullptr;
1621 }
1622
1623 RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1624 addSharedObject(o.get());
1625 return o;
1626}
1627
1628void WebGLRenderingContextBase::cullFace(GC3Denum mode)
1629{
1630 if (isContextLostOrPending())
1631 return;
1632 m_context->cullFace(mode);
1633}
1634
1635bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
1636{
1637 if (isContextLostOrPending() || !object)
1638 return false;
1639 if (!object->validate(contextGroup(), this)) {
1640 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1641 return false;
1642 }
1643 if (object->object()) {
1644 // We need to pass in context here because we want
1645 // things in this context unbound.
1646 object->deleteObject(graphicsContext3D());
1647 }
1648 return true;
1649}
1650
1651void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
1652{
1653 if (!deleteObject(buffer))
1654 return;
1655 if (m_boundArrayBuffer == buffer)
1656 m_boundArrayBuffer = 0;
1657
1658 m_boundVertexArrayObject->unbindBuffer(buffer);
1659}
1660
1661void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1662{
1663 if (!deleteObject(framebuffer))
1664 return;
1665 if (framebuffer == m_framebufferBinding) {
1666 m_framebufferBinding = 0;
1667 if (m_drawingBuffer) {
1668 m_drawingBuffer->setFramebufferBinding(0);
1669 // Have to call bindFramebuffer here to bind back to internal fbo.
1670 m_drawingBuffer->bind();
1671 } else
1672 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1673 }
1674}
1675
1676void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
1677{
1678 deleteObject(program);
1679 // We don't reset m_currentProgram to 0 here because the deletion of the
1680 // current program is delayed.
1681}
1682
1683void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1684{
1685 if (!deleteObject(renderbuffer))
1686 return;
1687 if (renderbuffer == m_renderbufferBinding)
1688 m_renderbufferBinding = 0;
1689 if (m_framebufferBinding)
1690 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1691}
1692
1693void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
1694{
1695 deleteObject(shader);
1696}
1697
1698void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
1699{
1700 if (!deleteObject(texture))
1701 return;
1702 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1703 if (texture == m_textureUnits[i].texture2DBinding)
1704 m_textureUnits[i].texture2DBinding = nullptr;
1705 if (texture == m_textureUnits[i].textureCubeMapBinding)
1706 m_textureUnits[i].textureCubeMapBinding = nullptr;
1707 }
1708 if (m_framebufferBinding)
1709 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1710}
1711
1712void WebGLRenderingContextBase::depthFunc(GC3Denum func)
1713{
1714 if (isContextLostOrPending())
1715 return;
1716 m_context->depthFunc(func);
1717}
1718
1719void WebGLRenderingContextBase::depthMask(GC3Dboolean flag)
1720{
1721 if (isContextLostOrPending())
1722 return;
1723 m_depthMask = flag;
1724 m_context->depthMask(flag);
1725}
1726
1727void WebGLRenderingContextBase::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1728{
1729 if (isContextLostOrPending())
1730 return;
1731 if (zNear > zFar) {
1732 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1733 return;
1734 }
1735 m_context->depthRange(zNear, zFar);
1736}
1737
1738void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1739{
1740 UNUSED_PARAM(ec);
1741 if (isContextLostOrPending() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1742 return;
1743 if (!program->detachShader(shader)) {
1744 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1745 return;
1746 }
1747 m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1748 shader->onDetached(graphicsContext3D());
1749}
1750
1751void WebGLRenderingContextBase::disable(GC3Denum cap)
1752{
1753 if (isContextLostOrPending() || !validateCapability("disable", cap))
1754 return;
1755 if (cap == GraphicsContext3D::STENCIL_TEST) {
1756 m_stencilEnabled = false;
1757 applyStencilTest();
1758 return;
1759 }
1760 if (cap == GraphicsContext3D::SCISSOR_TEST) {
1761 m_scissorEnabled = false;
1762 if (m_drawingBuffer)
1763 m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1764 }
1765 m_context->disable(cap);
1766}
1767
1768void WebGLRenderingContextBase::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1769{
1770 UNUSED_PARAM(ec);
1771 if (isContextLostOrPending())
1772 return;
1773 if (index >= m_maxVertexAttribs) {
1774 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1775 return;
1776 }
1777
1778 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1779 state.enabled = false;
1780
1781 if (index > 0 || isGLES2Compliant())
1782 m_context->disableVertexAttribArray(index);
1783}
1784
1785bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1786{
1787 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1788
1789 if (!elementArrayBuffer)
1790 return false;
1791
1792 if (offset < 0)
1793 return false;
1794
1795 if (type == GraphicsContext3D::UNSIGNED_INT) {
1796 // For an unsigned array, offset must be divisible by 4 for alignment reasons.
1797 if (offset % 4)
1798 return false;
1799
1800 // Make uoffset an element offset.
1801 offset /= 4;
1802
1803 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 4;
1804 if (offset > n || count > n - offset)
1805 return false;
1806 } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1807 // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1808 if (offset % 2)
1809 return false;
1810
1811 // Make uoffset an element offset.
1812 offset /= 2;
1813
1814 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1815 if (offset > n || count > n - offset)
1816 return false;
1817 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1818 GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1819 if (offset > n || count > n - offset)
1820 return false;
1821 }
1822 return true;
1823}
1824
1825bool WebGLRenderingContextBase::validateIndexArrayConservative(GC3Denum type, unsigned& numElementsRequired)
1826{
1827 // Performs conservative validation by caching a maximum index of
1828 // the given type per element array buffer. If all of the bound
1829 // array buffers have enough elements to satisfy that maximum
1830 // index, skips the expensive per-draw-call iteration in
1831 // validateIndexArrayPrecise.
1832
1833 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1834
1835 if (!elementArrayBuffer)
1836 return false;
1837
1838 GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1839 // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1840 if (!numElements)
1841 return false;
1842 const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1843 ASSERT(buffer);
1844
1845 int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1846 if (maxIndex < 0) {
1847 // Compute the maximum index in the entire buffer for the given type of index.
1848 switch (type) {
1849 case GraphicsContext3D::UNSIGNED_BYTE: {
1850 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1851 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1852 maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
1853 break;
1854 }
1855 case GraphicsContext3D::UNSIGNED_SHORT: {
1856 numElements /= sizeof(GC3Dushort);
1857 const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1858 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1859 maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
1860 break;
1861 }
1862 case GraphicsContext3D::UNSIGNED_INT: {
1863 if (!m_oesElementIndexUint)
1864 return false;
1865 numElements /= sizeof(GC3Duint);
1866 const GC3Duint* p = static_cast<const GC3Duint*>(buffer->data());
1867 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1868 maxIndex = std::max(maxIndex, static_cast<int>(p[i]));
1869 break;
1870 }
1871 default:
1872 return false;
1873 }
1874 elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1875 }
1876
1877 if (maxIndex >= 0) {
1878 // The number of required elements is one more than the maximum
1879 // index that will be accessed.
1880 numElementsRequired = maxIndex + 1;
1881 return true;
1882 }
1883
1884 return false;
1885}
1886
1887bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired)
1888{
1889 ASSERT(count >= 0 && offset >= 0);
1890 unsigned lastIndex = 0;
1891
1892 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1893
1894 if (!elementArrayBuffer)
1895 return false;
1896
1897 if (!count) {
1898 numElementsRequired = 0;
1899 return true;
1900 }
1901
1902 if (!elementArrayBuffer->elementArrayBuffer())
1903 return false;
1904
1905 unsigned long uoffset = offset;
1906 unsigned long n = count;
1907
1908 if (type == GraphicsContext3D::UNSIGNED_INT) {
1909 // Make uoffset an element offset.
1910 uoffset /= sizeof(GC3Duint);
1911 const GC3Duint* p = static_cast<const GC3Duint*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1912 while (n-- > 0) {
1913 if (*p > lastIndex)
1914 lastIndex = *p;
1915 ++p;
1916 }
1917 } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1918 // Make uoffset an element offset.
1919 uoffset /= sizeof(GC3Dushort);
1920 const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1921 while (n-- > 0) {
1922 if (*p > lastIndex)
1923 lastIndex = *p;
1924 ++p;
1925 }
1926 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1927 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1928 while (n-- > 0) {
1929 if (*p > lastIndex)
1930 lastIndex = *p;
1931 ++p;
1932 }
1933 }
1934
1935 // Then set the last index in the index array and make sure it is valid.
1936 numElementsRequired = lastIndex + 1;
1937 return numElementsRequired > 0;
1938}
1939
1940bool WebGLRenderingContextBase::validateVertexAttributes(unsigned elementCount, unsigned primitiveCount)
1941{
1942 if (!m_currentProgram)
1943 return false;
1944
1945 // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1946 for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1947 if (!m_boundVertexArrayObject->getVertexAttribState(i).validateBinding())
1948 return false;
1949 }
1950
1951 if (elementCount <= 0)
1952 return true;
1953
1954
1955 // Look in each consumed vertex attrib (by the current program).
1956 bool sawNonInstancedAttrib = false;
1957 bool sawEnabledAttrib = false;
1958 int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1959 for (int i = 0; i < numActiveAttribLocations; ++i) {
1960 int loc = m_currentProgram->getActiveAttribLocation(i);
1961 if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1962 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1963 if (state.enabled) {
1964 sawEnabledAttrib = true;
1965 // Avoid off-by-one errors in numElements computation.
1966 // For the last element, we will only touch the data for the
1967 // element and nothing beyond it.
1968 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1969 unsigned numElements = 0;
1970 ASSERT(state.stride > 0);
1971 if (bytesRemaining >= state.bytesPerElement)
1972 numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1973 unsigned instancesRequired = 0;
1974 if (state.divisor) {
1975 instancesRequired = ceil(static_cast<float>(primitiveCount) / state.divisor);
1976 if (instancesRequired > numElements)
1977 return false;
1978 } else {
1979 sawNonInstancedAttrib = true;
1980 if (elementCount > numElements)
1981 return false;
1982 }
1983 }
1984 }
1985 }
1986
1987 if (!sawNonInstancedAttrib && sawEnabledAttrib)
1988 return false;
1989
1990 return true;
1991}
1992
1993bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
1994{
1995 if (!object || !object->object()) {
1996 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1997 return false;
1998 }
1999 if (!object->validate(contextGroup(), this)) {
2000 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
2001 return false;
2002 }
2003 return true;
2004}
2005
2006bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primitiveCount)
2007{
2008 if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
2009 return false;
2010
2011 if (!validateStencilSettings(functionName))
2012 return false;
2013
2014 if (first < 0 || count < 0) {
2015 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "first or count < 0");
2016 return false;
2017 }
2018
2019 if (!count) {
2020 markContextChanged();
2021 return false;
2022 }
2023
2024 if (primitiveCount < 0) {
2025 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
2026 return false;
2027 }
2028
2029 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
2030 // Ensure we have a valid rendering state
2031 Checked<GC3Dint, RecordOverflow> checkedFirst(first);
2032 Checked<GC3Dint, RecordOverflow> checkedCount(count);
2033 Checked<GC3Dint, RecordOverflow> checkedSum = checkedFirst + checkedCount;
2034 Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
2035 if (checkedSum.hasOverflowed() || checkedPrimitiveCount.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet(), checkedPrimitiveCount.unsafeGet())) {
2036 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
2037 return false;
2038 }
2039 } else {
2040 if (!validateVertexAttributes(0)) {
2041 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
2042 return false;
2043 }
2044 }
2045
2046 const char* reason = "framebuffer incomplete";
2047 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
2048 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
2049 return false;
2050 }
2051
2052 return true;
2053}
2054
2055void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
2056{
2057 UNUSED_PARAM(ec);
2058
2059 if (!validateDrawArrays("drawArrays", mode, first, count, 0))
2060 return;
2061
2062 clearIfComposited();
2063
2064 bool vertexAttrib0Simulated = false;
2065 if (!isGLES2Compliant())
2066 vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
2067 if (!isGLES2NPOTStrict())
2068 checkTextureCompleteness("drawArrays", true);
2069
2070 m_context->drawArrays(mode, first, count);
2071
2072 if (!isGLES2Compliant() && vertexAttrib0Simulated)
2073 restoreStatesAfterVertexAttrib0Simulation();
2074 if (!isGLES2NPOTStrict())
2075 checkTextureCompleteness("drawArrays", false);
2076 markContextChanged();
2077}
2078
2079bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
2080{
2081 if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
2082 return false;
2083
2084 if (!validateStencilSettings(functionName))
2085 return false;
2086
2087 switch (type) {
2088 case GraphicsContext3D::UNSIGNED_BYTE:
2089 case GraphicsContext3D::UNSIGNED_SHORT:
2090 break;
2091 case GraphicsContext3D::UNSIGNED_INT:
2092 if (m_oesElementIndexUint)
2093 break;
2094 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
2095 return false;
2096 default:
2097 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
2098 return false;
2099 }
2100
2101 if (count < 0 || offset < 0) {
2102 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
2103 return false;
2104 }
2105
2106 if (!count) {
2107 markContextChanged();
2108 return false;
2109 }
2110
2111 if (primitiveCount < 0) {
2112 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
2113 return false;
2114 }
2115
2116 if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
2117 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
2118 return false;
2119 }
2120
2121 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
2122 // Ensure we have a valid rendering state
2123 if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
2124 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
2125 return false;
2126 }
2127 if (!count)
2128 return false;
2129
2130 Checked<GC3Dint, RecordOverflow> checkedCount(count);
2131 Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
2132 if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
2133 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
2134 return false;
2135 }
2136
2137 if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
2138 if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
2139 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
2140 return false;
2141 }
2142 }
2143 } else {
2144 if (!validateVertexAttributes(0)) {
2145 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
2146 return false;
2147 }
2148 }
2149
2150 const char* reason = "framebuffer incomplete";
2151 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
2152 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
2153 return false;
2154 }
2155
2156 return true;
2157}
2158
2159void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
2160{
2161 UNUSED_PARAM(ec);
2162
2163 unsigned numElements = 0;
2164 if (!validateDrawElements("drawElements", mode, count, type, offset, numElements, 0))
2165 return;
2166
2167 clearIfComposited();
2168
2169 bool vertexAttrib0Simulated = false;
2170 if (!isGLES2Compliant()) {
2171 if (!numElements)
2172 validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
2173 vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
2174 }
2175 if (!isGLES2NPOTStrict())
2176 checkTextureCompleteness("drawElements", true);
2177
2178 m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
2179
2180 if (!isGLES2Compliant() && vertexAttrib0Simulated)
2181 restoreStatesAfterVertexAttrib0Simulation();
2182 if (!isGLES2NPOTStrict())
2183 checkTextureCompleteness("drawElements", false);
2184 markContextChanged();
2185}
2186
2187void WebGLRenderingContextBase::enable(GC3Denum cap)
2188{
2189 if (isContextLostOrPending() || !validateCapability("enable", cap))
2190 return;
2191 if (cap == GraphicsContext3D::STENCIL_TEST) {
2192 m_stencilEnabled = true;
2193 applyStencilTest();
2194 return;
2195 }
2196 if (cap == GraphicsContext3D::SCISSOR_TEST) {
2197 m_scissorEnabled = true;
2198 if (m_drawingBuffer)
2199 m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
2200 }
2201 m_context->enable(cap);
2202}
2203
2204void WebGLRenderingContextBase::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
2205{
2206 UNUSED_PARAM(ec);
2207 if (isContextLostOrPending())
2208 return;
2209 if (index >= m_maxVertexAttribs) {
2210 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
2211 return;
2212 }
2213
2214 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2215 state.enabled = true;
2216
2217 m_context->enableVertexAttribArray(index);
2218}
2219
2220void WebGLRenderingContextBase::finish()
2221{
2222 if (isContextLostOrPending())
2223 return;
2224 m_context->finish();
2225}
2226
2227void WebGLRenderingContextBase::flush()
2228{
2229 if (isContextLostOrPending())
2230 return;
2231 m_context->flush();
2232}
2233
2234void WebGLRenderingContextBase::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
2235{
2236 UNUSED_PARAM(ec);
2237 if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2238 return;
2239 if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2240 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2241 return;
2242 }
2243 if (buffer && !buffer->validate(contextGroup(), this)) {
2244 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2245 return;
2246 }
2247 // Don't allow the default framebuffer to be mutated; all current
2248 // implementations use an FBO internally in place of the default
2249 // FBO.
2250 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2251 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2252 return;
2253 }
2254 Platform3DObject bufferObject = objectOrZero(buffer);
2255 switch (attachment) {
2256 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2257 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2258 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2259 break;
2260 default:
2261 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
2262 }
2263 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2264 applyStencilTest();
2265}
2266
2267void WebGLRenderingContextBase::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
2268{
2269 UNUSED_PARAM(ec);
2270 if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2271 return;
2272 if (level) {
2273 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2274 return;
2275 }
2276 if (texture && !texture->validate(contextGroup(), this)) {
2277 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2278 return;
2279 }
2280 // Don't allow the default framebuffer to be mutated; all current
2281 // implementations use an FBO internally in place of the default
2282 // FBO.
2283 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2284 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2285 return;
2286 }
2287 Platform3DObject textureObject = objectOrZero(texture);
2288 switch (attachment) {
2289 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2290 m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
2291 m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
2292 break;
2293 case GraphicsContext3D::DEPTH_ATTACHMENT:
2294 m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2295 break;
2296 case GraphicsContext3D::STENCIL_ATTACHMENT:
2297 m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2298 break;
2299 default:
2300 m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2301 }
2302 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2303 applyStencilTest();
2304}
2305
2306void WebGLRenderingContextBase::frontFace(GC3Denum mode)
2307{
2308 if (isContextLostOrPending())
2309 return;
2310 m_context->frontFace(mode);
2311}
2312
2313void WebGLRenderingContextBase::generateMipmap(GC3Denum target)
2314{
2315 if (isContextLostOrPending())
2316 return;
2317 WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2318 if (!tex)
2319 return;
2320 if (!tex->canGenerateMipmaps()) {
2321 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2322 return;
2323 }
2324 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=123916. Compressed textures should be allowed in WebGL 2:
2325 if (tex->isCompressed()) {
2326 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "trying to generate mipmaps from compressed texture");
2327 return;
2328 }
2329 if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2330 return;
2331
2332 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2333 // on Mac. Remove the hack once this driver bug is fixed.
2334#if OS(DARWIN)
2335 bool needToResetMinFilter = false;
2336 if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2337 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2338 needToResetMinFilter = true;
2339 }
2340#endif
2341 m_context->generateMipmap(target);
2342#if OS(DARWIN)
2343 if (needToResetMinFilter)
2344 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2345#endif
2346 tex->generateMipmapLevelInfo();
2347}
2348
2349PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2350{
2351 UNUSED_PARAM(ec);
2352 if (isContextLostOrPending() || !validateWebGLObject("getActiveAttrib", program))
2353 return nullptr;
2354 ActiveInfo info;
2355 if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2356 return nullptr;
2357
2358 LOG(WebGL, "Returning active attribute %d: %s", index, info.name.utf8().data());
2359
2360 return WebGLActiveInfo::create(info.name, info.type, info.size);
2361}
2362
2363PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2364{
2365 UNUSED_PARAM(ec);
2366 if (isContextLostOrPending() || !validateWebGLObject("getActiveUniform", program))
2367 return 0;
2368 ActiveInfo info;
2369 if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2370 return nullptr;
2371 if (!isGLES2Compliant()) {
2372 if (info.size > 1 && !info.name.endsWith("[0]"))
2373 info.name.append("[0]");
2374 }
2375
2376 LOG(WebGL, "Returning active uniform %d: %s", index, info.name.utf8().data());
2377
2378 return WebGLActiveInfo::create(info.name, info.type, info.size);
2379}
2380
2381bool WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader>>& shaderObjects, ExceptionCode& ec)
2382{
2383 UNUSED_PARAM(ec);
2384 shaderObjects.clear();
2385 if (isContextLostOrPending() || !validateWebGLObject("getAttachedShaders", program))
2386 return false;
2387
2388 const GC3Denum shaderType[] = {
2389 GraphicsContext3D::VERTEX_SHADER,
2390 GraphicsContext3D::FRAGMENT_SHADER
2391 };
2392 for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2393 WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2394 if (shader)
2395 shaderObjects.append(shader);
2396 }
2397 return true;
2398}
2399
2400GC3Dint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name)
2401{
2402 if (isContextLostOrPending() || !validateWebGLObject("getAttribLocation", program))
2403 return -1;
2404 if (!validateLocationLength("getAttribLocation", name))
2405 return -1;
2406 if (!validateString("getAttribLocation", name))
2407 return -1;
2408 if (isPrefixReserved(name))
2409 return -1;
2410 if (!program->getLinkStatus()) {
2411 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2412 return -1;
2413 }
2414 return m_context->getAttribLocation(objectOrZero(program), name);
2415}
2416
2417WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2418{
2419 UNUSED_PARAM(ec);
2420 if (isContextLostOrPending())
2421 return WebGLGetInfo();
2422 if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2423 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2424 return WebGLGetInfo();
2425 }
2426
2427 if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2428 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2429 return WebGLGetInfo();
2430 }
2431
2432 GC3Dint value = 0;
2433 m_context->getBufferParameteriv(target, pname, &value);
2434 if (pname == GraphicsContext3D::BUFFER_SIZE)
2435 return WebGLGetInfo(value);
2436 return WebGLGetInfo(static_cast<unsigned>(value));
2437}
2438
2439PassRefPtr<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes()
2440{
2441 if (isContextLostOrPending())
2442 return nullptr;
2443 // We always need to return a new WebGLContextAttributes object to
2444 // prevent the user from mutating any cached version.
2445
2446 // Also, we need to enforce requested values of "false" for depth
2447 // and stencil, regardless of the properties of the underlying
2448 // GraphicsContext3D or DrawingBuffer.
2449 RefPtr<WebGLContextAttributes> attributes = WebGLContextAttributes::create(m_context->getContextAttributes());
2450 if (!m_attributes.depth)
2451 attributes->setDepth(false);
2452 if (!m_attributes.stencil)
2453 attributes->setStencil(false);
2454 if (m_drawingBuffer) {
2455 // The DrawingBuffer obtains its parameters from GraphicsContext3D::getContextAttributes(),
2456 // but it makes its own determination of whether multisampling is supported.
2457 attributes->setAntialias(m_drawingBuffer->multisample());
2458 }
2459 return attributes.release();
2460}
2461
2462GC3Denum WebGLRenderingContextBase::getError()
2463{
2464 if (m_isPendingPolicyResolution)
2465 return GraphicsContext3D::NO_ERROR;
2466 return m_context->getError();
2467}
2468
2469WebGLExtension* WebGLRenderingContextBase::getExtension(const String& name)
2470{
2471 if (isContextLostOrPending())
2472 return nullptr;
2473
2474 if (equalIgnoringCase(name, "EXT_blend_minmax")
2475 && m_context->getExtensions()->supports("GL_EXT_blend_minmax")) {
2476 if (!m_extBlendMinMax) {
2477 m_context->getExtensions()->ensureEnabled("GL_EXT_blend_minmax");
2478 m_extBlendMinMax = std::make_unique<EXTBlendMinMax>(this);
2479 }
2480 return m_extBlendMinMax.get();
2481 }
2482 if (equalIgnoringCase(name, "EXT_sRGB")
2483 && m_context->getExtensions()->supports("GL_EXT_sRGB")) {
2484 if (!m_extsRGB) {
2485 m_context->getExtensions()->ensureEnabled("GL_EXT_sRGB");
2486 m_extsRGB = std::make_unique<EXTsRGB>(this);
2487 }
2488 return m_extsRGB.get();
2489 }
2490 if (equalIgnoringCase(name, "EXT_frag_depth")
2491 && m_context->getExtensions()->supports("GL_EXT_frag_depth")) {
2492 if (!m_extFragDepth) {
2493 m_context->getExtensions()->ensureEnabled("GL_EXT_frag_depth");
2494 m_extFragDepth = std::make_unique<EXTFragDepth>(this);
2495 }
2496 return m_extFragDepth.get();
2497 }
2498 if (equalIgnoringCase(name, "EXT_shader_texture_lod")
2499 && (m_context->getExtensions()->supports("GL_EXT_shader_texture_lod") || m_context->getExtensions()->supports("GL_ARB_shader_texture_lod"))) {
2500 if (!m_extShaderTextureLOD) {
2501 m_context->getExtensions()->ensureEnabled("GL_EXT_shader_texture_lod");
2502 m_extShaderTextureLOD = std::make_unique<EXTShaderTextureLOD>(this);
2503 }
2504 return m_extShaderTextureLOD.get();
2505 }
2506 if (equalIgnoringCase(name, "WEBKIT_EXT_texture_filter_anisotropic")
2507 && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
2508 if (!m_extTextureFilterAnisotropic) {
2509 m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
2510 m_extTextureFilterAnisotropic = std::make_unique<EXTTextureFilterAnisotropic>(this);
2511 }
2512 return m_extTextureFilterAnisotropic.get();
2513 }
2514 if (equalIgnoringCase(name, "OES_standard_derivatives")
2515 && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
2516 if (!m_oesStandardDerivatives) {
2517 m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
2518 m_oesStandardDerivatives = std::make_unique<OESStandardDerivatives>(this);
2519 }
2520 return m_oesStandardDerivatives.get();
2521 }
2522 if (equalIgnoringCase(name, "OES_texture_float")
2523 && m_context->getExtensions()->supports("GL_OES_texture_float")) {
2524 if (!m_oesTextureFloat) {
2525 m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
2526 m_oesTextureFloat = std::make_unique<OESTextureFloat>(this);
2527 }
2528 return m_oesTextureFloat.get();
2529 }
2530 if (equalIgnoringCase(name, "OES_texture_float_linear")
2531 && m_context->getExtensions()->supports("GL_OES_texture_float_linear")) {
2532 if (!m_oesTextureFloatLinear) {
2533 m_context->getExtensions()->ensureEnabled("GL_OES_texture_float_linear");
2534 m_oesTextureFloatLinear = std::make_unique<OESTextureFloatLinear>(this);
2535 }
2536 return m_oesTextureFloatLinear.get();
2537 }
2538 if (equalIgnoringCase(name, "OES_texture_half_float")
2539 && m_context->getExtensions()->supports("GL_OES_texture_half_float")) {
2540 if (!m_oesTextureHalfFloat) {
2541 m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float");
2542 m_oesTextureHalfFloat = std::make_unique<OESTextureHalfFloat>(this);
2543 }
2544 return m_oesTextureHalfFloat.get();
2545 }
2546 if (equalIgnoringCase(name, "OES_texture_half_float_linear")
2547 && m_context->getExtensions()->supports("GL_OES_texture_half_float_linear")) {
2548 if (!m_oesTextureHalfFloatLinear) {
2549 m_context->getExtensions()->ensureEnabled("GL_OES_texture_half_float_linear");
2550 m_oesTextureHalfFloatLinear = std::make_unique<OESTextureHalfFloatLinear>(this);
2551 }
2552 return m_oesTextureHalfFloatLinear.get();
2553 }
2554 if (equalIgnoringCase(name, "OES_vertex_array_object")
2555 && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
2556 if (!m_oesVertexArrayObject) {
2557 m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
2558 m_oesVertexArrayObject = std::make_unique<OESVertexArrayObject>(this);
2559 }
2560 return m_oesVertexArrayObject.get();
2561 }
2562 if (equalIgnoringCase(name, "OES_element_index_uint")
2563 && m_context->getExtensions()->supports("GL_OES_element_index_uint")) {
2564 if (!m_oesElementIndexUint) {
2565 m_context->getExtensions()->ensureEnabled("GL_OES_element_index_uint");
2566 m_oesElementIndexUint = std::make_unique<OESElementIndexUint>(this);
2567 }
2568 return m_oesElementIndexUint.get();
2569 }
2570 if (equalIgnoringCase(name, "WEBGL_lose_context")) {
2571 if (!m_webglLoseContext)
2572 m_webglLoseContext = std::make_unique<WebGLLoseContext>(this);
2573 return m_webglLoseContext.get();
2574 }
2575 if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_atc"))
2576 && WebGLCompressedTextureATC::supported(this)) {
2577 if (!m_webglCompressedTextureATC)
2578 m_webglCompressedTextureATC = std::make_unique<WebGLCompressedTextureATC>(this);
2579 return m_webglCompressedTextureATC.get();
2580 }
2581 if ((equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_pvrtc"))
2582 && WebGLCompressedTexturePVRTC::supported(this)) {
2583 if (!m_webglCompressedTexturePVRTC)
2584 m_webglCompressedTexturePVRTC = std::make_unique<WebGLCompressedTexturePVRTC>(this);
2585 return m_webglCompressedTexturePVRTC.get();
2586 }
2587 if (equalIgnoringCase(name, "WEBGL_compressed_texture_s3tc")
2588 && WebGLCompressedTextureS3TC::supported(this)) {
2589 if (!m_webglCompressedTextureS3TC)
2590 m_webglCompressedTextureS3TC = std::make_unique<WebGLCompressedTextureS3TC>(this);
2591 return m_webglCompressedTextureS3TC.get();
2592 }
2593 if (equalIgnoringCase(name, "WEBGL_depth_texture")
2594 && WebGLDepthTexture::supported(graphicsContext3D())) {
2595 if (!m_webglDepthTexture) {
2596 m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
2597 m_webglDepthTexture = std::make_unique<WebGLDepthTexture>(this);
2598 }
2599 return m_webglDepthTexture.get();
2600 }
2601 if (equalIgnoringCase(name, "WEBGL_draw_buffers") && supportsDrawBuffers()) {
2602 if (!m_webglDrawBuffers) {
2603 m_context->getExtensions()->ensureEnabled("GL_EXT_draw_buffers");
2604 m_webglDrawBuffers = std::make_unique<WebGLDrawBuffers>(this);
2605 }
2606 return m_webglDrawBuffers.get();
2607 }
2608 if (equalIgnoringCase(name, "ANGLE_instanced_arrays") && ANGLEInstancedArrays::supported(this)) {
2609 if (!m_angleInstancedArrays) {
2610 m_context->getExtensions()->ensureEnabled("GL_ANGLE_instanced_arrays");
2611 m_angleInstancedArrays = std::make_unique<ANGLEInstancedArrays>(this);
2612 }
2613 return m_angleInstancedArrays.get();
2614 }
2615 if (allowPrivilegedExtensions()) {
2616 if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
2617 if (!m_webglDebugRendererInfo)
2618 m_webglDebugRendererInfo = std::make_unique<WebGLDebugRendererInfo>(this);
2619 return m_webglDebugRendererInfo.get();
2620 }
2621 if (equalIgnoringCase(name, "WEBGL_debug_shaders")
2622 && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
2623 if (!m_webglDebugShaders)
2624 m_webglDebugShaders = std::make_unique<WebGLDebugShaders>(this);
2625 return m_webglDebugShaders.get();
2626 }
2627 }
2628
2629 return nullptr;
2630}
2631
2632WebGLGetInfo WebGLRenderingContextBase::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2633{
2634 UNUSED_PARAM(ec);
2635 if (isContextLostOrPending() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2636 return WebGLGetInfo();
2637
2638 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2639 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2640 return WebGLGetInfo();
2641 }
2642
2643 WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
2644 if (!object) {
2645 if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2646 return WebGLGetInfo(GraphicsContext3D::NONE);
2647 // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2648 // specifies INVALID_OPERATION.
2649 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2650 return WebGLGetInfo();
2651 }
2652
2653 ASSERT(object->isTexture() || object->isRenderbuffer());
2654 if (object->isTexture()) {
2655 switch (pname) {
2656 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2657 return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2658 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2659 return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2660 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2661 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2662 case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
2663 GC3Dint value = 0;
2664 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2665 return WebGLGetInfo(value);
2666 }
2667 default:
2668 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2669 return WebGLGetInfo();
2670 }
2671 } else {
2672 switch (pname) {
2673 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2674 return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2675 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2676 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2677 case Extensions3D::FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT: {
2678 WebGLRenderbuffer* renderBuffer = reinterpret_cast<WebGLRenderbuffer*>(object);
2679 GC3Denum renderBufferFormat = renderBuffer->getInternalFormat();
2680 ASSERT(renderBufferFormat != Extensions3D::SRGB_EXT && renderBufferFormat != Extensions3D::SRGB_ALPHA_EXT);
2681 if (renderBufferFormat == Extensions3D::SRGB8_ALPHA8_EXT)
2682 return WebGLGetInfo(Extensions3D::SRGB_EXT);
2683 return WebGLGetInfo(GraphicsContext3D::LINEAR);
2684 }
2685 default:
2686 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2687 return WebGLGetInfo();
2688 }
2689 }
2690}
2691
2692WebGLGetInfo WebGLRenderingContextBase::getParameter(GC3Denum pname, ExceptionCode& ec)
2693{
2694 UNUSED_PARAM(ec);
2695 if (isContextLostOrPending())
2696 return WebGLGetInfo();
2697 const int intZero = 0;
2698 switch (pname) {
2699 case GraphicsContext3D::ACTIVE_TEXTURE:
2700 return getUnsignedIntParameter(pname);
2701 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2702 return getWebGLFloatArrayParameter(pname);
2703 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2704 return getWebGLFloatArrayParameter(pname);
2705 case GraphicsContext3D::ALPHA_BITS:
2706 return getIntParameter(pname);
2707 case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2708 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2709 case GraphicsContext3D::BLEND:
2710 return getBooleanParameter(pname);
2711 case GraphicsContext3D::BLEND_COLOR:
2712 return getWebGLFloatArrayParameter(pname);
2713 case GraphicsContext3D::BLEND_DST_ALPHA:
2714 return getUnsignedIntParameter(pname);
2715 case GraphicsContext3D::BLEND_DST_RGB:
2716 return getUnsignedIntParameter(pname);
2717 case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2718 return getUnsignedIntParameter(pname);
2719 case GraphicsContext3D::BLEND_EQUATION_RGB:
2720 return getUnsignedIntParameter(pname);
2721 case GraphicsContext3D::BLEND_SRC_ALPHA:
2722 return getUnsignedIntParameter(pname);
2723 case GraphicsContext3D::BLEND_SRC_RGB:
2724 return getUnsignedIntParameter(pname);
2725 case GraphicsContext3D::BLUE_BITS:
2726 return getIntParameter(pname);
2727 case GraphicsContext3D::COLOR_CLEAR_VALUE:
2728 return getWebGLFloatArrayParameter(pname);
2729 case GraphicsContext3D::COLOR_WRITEMASK:
2730 return getBooleanArrayParameter(pname);
2731 case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2732 return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2733 case GraphicsContext3D::CULL_FACE:
2734 return getBooleanParameter(pname);
2735 case GraphicsContext3D::CULL_FACE_MODE:
2736 return getUnsignedIntParameter(pname);
2737 case GraphicsContext3D::CURRENT_PROGRAM:
2738 return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2739 case GraphicsContext3D::DEPTH_BITS:
2740 if (!m_framebufferBinding && !m_attributes.depth)
2741 return WebGLGetInfo(intZero);
2742 return getIntParameter(pname);
2743 case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2744 return getFloatParameter(pname);
2745 case GraphicsContext3D::DEPTH_FUNC:
2746 return getUnsignedIntParameter(pname);
2747 case GraphicsContext3D::DEPTH_RANGE:
2748 return getWebGLFloatArrayParameter(pname);
2749 case GraphicsContext3D::DEPTH_TEST:
2750 return getBooleanParameter(pname);
2751 case GraphicsContext3D::DEPTH_WRITEMASK:
2752 return getBooleanParameter(pname);
2753 case GraphicsContext3D::DITHER:
2754 return getBooleanParameter(pname);
2755 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2756 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2757 case GraphicsContext3D::FRAMEBUFFER_BINDING:
2758 return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2759 case GraphicsContext3D::FRONT_FACE:
2760 return getUnsignedIntParameter(pname);
2761 case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2762 return getUnsignedIntParameter(pname);
2763 case GraphicsContext3D::GREEN_BITS:
2764 return getIntParameter(pname);
2765 case GraphicsContext3D::LINE_WIDTH:
2766 return getFloatParameter(pname);
2767 case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2768 return getIntParameter(pname);
2769 case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2770 return getIntParameter(pname);
2771 case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2772 return getIntParameter(pname);
2773 case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2774 return getIntParameter(pname);
2775 case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2776 return getIntParameter(pname);
2777 case GraphicsContext3D::MAX_TEXTURE_SIZE:
2778 return getIntParameter(pname);
2779 case GraphicsContext3D::MAX_VARYING_VECTORS:
2780 return getIntParameter(pname);
2781 case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2782 return getIntParameter(pname);
2783 case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2784 return getIntParameter(pname);
2785 case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2786 return getIntParameter(pname);
2787 case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2788 return getWebGLIntArrayParameter(pname);
2789 case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2790 // FIXME: should we always return 0 for this?
2791 return getIntParameter(pname);
2792 case GraphicsContext3D::PACK_ALIGNMENT:
2793 return getIntParameter(pname);
2794 case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2795 return getFloatParameter(pname);
2796 case GraphicsContext3D::POLYGON_OFFSET_FILL:
2797 return getBooleanParameter(pname);
2798 case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2799 return getFloatParameter(pname);
2800 case GraphicsContext3D::RED_BITS:
2801 return getIntParameter(pname);
2802 case GraphicsContext3D::RENDERBUFFER_BINDING:
2803 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2804 case GraphicsContext3D::RENDERER:
2805 return WebGLGetInfo(String("WebKit WebGL"));
2806 case GraphicsContext3D::SAMPLE_BUFFERS:
2807 return getIntParameter(pname);
2808 case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2809 return getBooleanParameter(pname);
2810 case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2811 return getFloatParameter(pname);
2812 case GraphicsContext3D::SAMPLES:
2813 return getIntParameter(pname);
2814 case GraphicsContext3D::SCISSOR_BOX:
2815 return getWebGLIntArrayParameter(pname);
2816 case GraphicsContext3D::SCISSOR_TEST:
2817 return getBooleanParameter(pname);
2818 case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2819 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2820 case GraphicsContext3D::STENCIL_BACK_FAIL:
2821 return getUnsignedIntParameter(pname);
2822 case GraphicsContext3D::STENCIL_BACK_FUNC:
2823 return getUnsignedIntParameter(pname);
2824 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2825 return getUnsignedIntParameter(pname);
2826 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2827 return getUnsignedIntParameter(pname);
2828 case GraphicsContext3D::STENCIL_BACK_REF:
2829 return getIntParameter(pname);
2830 case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2831 return getUnsignedIntParameter(pname);
2832 case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2833 return getUnsignedIntParameter(pname);
2834 case GraphicsContext3D::STENCIL_BITS:
2835 if (!m_framebufferBinding && !m_attributes.stencil)
2836 return WebGLGetInfo(intZero);
2837 return getIntParameter(pname);
2838 case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2839 return getIntParameter(pname);
2840 case GraphicsContext3D::STENCIL_FAIL:
2841 return getUnsignedIntParameter(pname);
2842 case GraphicsContext3D::STENCIL_FUNC:
2843 return getUnsignedIntParameter(pname);
2844 case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2845 return getUnsignedIntParameter(pname);
2846 case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2847 return getUnsignedIntParameter(pname);
2848 case GraphicsContext3D::STENCIL_REF:
2849 return getIntParameter(pname);
2850 case GraphicsContext3D::STENCIL_TEST:
2851 return getBooleanParameter(pname);
2852 case GraphicsContext3D::STENCIL_VALUE_MASK:
2853 return getUnsignedIntParameter(pname);
2854 case GraphicsContext3D::STENCIL_WRITEMASK:
2855 return getUnsignedIntParameter(pname);
2856 case GraphicsContext3D::SUBPIXEL_BITS:
2857 return getIntParameter(pname);
2858 case GraphicsContext3D::TEXTURE_BINDING_2D:
2859 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].texture2DBinding));
2860 case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2861 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].textureCubeMapBinding));
2862 case GraphicsContext3D::UNPACK_ALIGNMENT:
2863 return getIntParameter(pname);
2864 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2865 return WebGLGetInfo(m_unpackFlipY);
2866 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2867 return WebGLGetInfo(m_unpackPremultiplyAlpha);
2868 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2869 return WebGLGetInfo(m_unpackColorspaceConversion);
2870 case GraphicsContext3D::VENDOR:
2871 return WebGLGetInfo(String("WebKit"));
2872 case GraphicsContext3D::VERSION:
2873 return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2874 case GraphicsContext3D::VIEWPORT:
2875 return getWebGLIntArrayParameter(pname);
2876 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2877 if (m_oesStandardDerivatives)
2878 return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2879 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2880 return WebGLGetInfo();
2881 case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2882 if (m_webglDebugRendererInfo)
2883 return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2884 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2885 return WebGLGetInfo();
2886 case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2887 if (m_webglDebugRendererInfo)
2888 return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
2889 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2890 return WebGLGetInfo();
2891 case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2892 if (m_oesVertexArrayObject) {
2893 if (!m_boundVertexArrayObject->isDefaultObject())
2894 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2895 return WebGLGetInfo();
2896 }
2897 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2898 return WebGLGetInfo();
2899 case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2900 if (m_extTextureFilterAnisotropic)
2901 return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2902 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2903 return WebGLGetInfo();
2904 case Extensions3D::MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
2905 if (m_webglDrawBuffers)
2906 return WebGLGetInfo(getMaxColorAttachments());
2907 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
2908 return WebGLGetInfo();
2909 case Extensions3D::MAX_DRAW_BUFFERS_EXT:
2910 if (m_webglDrawBuffers)
2911 return WebGLGetInfo(getMaxDrawBuffers());
2912 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
2913 return WebGLGetInfo();
2914 default:
2915 if (m_webglDrawBuffers
2916 && pname >= Extensions3D::DRAW_BUFFER0_EXT
2917 && pname < static_cast<GC3Denum>(Extensions3D::DRAW_BUFFER0_EXT + getMaxDrawBuffers())) {
2918 GC3Dint value = GraphicsContext3D::NONE;
2919 if (m_framebufferBinding)
2920 value = m_framebufferBinding->getDrawBuffer(pname);
2921 else // emulated backbuffer
2922 value = m_backDrawBuffer;
2923 return WebGLGetInfo(value);
2924 }
2925 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
2926 return WebGLGetInfo();
2927 }
2928}
2929
2930WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2931{
2932 UNUSED_PARAM(ec);
2933 if (isContextLostOrPending() || !validateWebGLObject("getProgramParameter", program))
2934 return WebGLGetInfo();
2935
2936 GC3Dint value = 0;
2937 switch (pname) {
2938 case GraphicsContext3D::DELETE_STATUS:
2939 return WebGLGetInfo(program->isDeleted());
2940 case GraphicsContext3D::VALIDATE_STATUS:
2941 m_context->getProgramiv(objectOrZero(program), pname, &value);
2942 return WebGLGetInfo(static_cast<bool>(value));
2943 case GraphicsContext3D::LINK_STATUS:
2944 return WebGLGetInfo(program->getLinkStatus());
2945 case GraphicsContext3D::ATTACHED_SHADERS:
2946 m_context->getProgramiv(objectOrZero(program), pname, &value);
2947 return WebGLGetInfo(value);
2948 case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2949 case GraphicsContext3D::ACTIVE_UNIFORMS:
2950 m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), pname, &value);
2951 return WebGLGetInfo(value);
2952 default:
2953 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2954 return WebGLGetInfo();
2955 }
2956}
2957
2958String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2959{
2960 UNUSED_PARAM(ec);
2961 if (isContextLostOrPending())
2962 return String();
2963 if (!validateWebGLObject("getProgramInfoLog", program))
2964 return "";
2965 return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2966}
2967
2968WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2969{
2970 UNUSED_PARAM(ec);
2971 if (isContextLostOrPending())
2972 return WebGLGetInfo();
2973 if (target != GraphicsContext3D::RENDERBUFFER) {
2974 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2975 return WebGLGetInfo();
2976 }
2977 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2978 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2979 return WebGLGetInfo();
2980 }
2981
2982 if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2983 && !m_renderbufferBinding->isValid()) {
2984 ASSERT(!isDepthStencilSupported());
2985 int value = 0;
2986 switch (pname) {
2987 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2988 value = m_renderbufferBinding->getWidth();
2989 break;
2990 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2991 value = m_renderbufferBinding->getHeight();
2992 break;
2993 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2994 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2995 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2996 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2997 value = 0;
2998 break;
2999 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
3000 value = 24;
3001 break;
3002 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
3003 value = 8;
3004 break;
3005 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
3006 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
3007 default:
3008 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
3009 return WebGLGetInfo();
3010 }
3011 return WebGLGetInfo(value);
3012 }
3013
3014 GC3Dint value = 0;
3015 switch (pname) {
3016 case GraphicsContext3D::RENDERBUFFER_WIDTH:
3017 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
3018 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
3019 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
3020 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
3021 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
3022 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
3023 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
3024 m_context->getRenderbufferParameteriv(target, pname, &value);
3025 return WebGLGetInfo(value);
3026 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
3027 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
3028 default:
3029 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
3030 return WebGLGetInfo();
3031 }
3032}
3033
3034WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
3035{
3036 UNUSED_PARAM(ec);
3037 if (isContextLostOrPending() || !validateWebGLObject("getShaderParameter", shader))
3038 return WebGLGetInfo();
3039 GC3Dint value = 0;
3040 switch (pname) {
3041 case GraphicsContext3D::DELETE_STATUS:
3042 return WebGLGetInfo(shader->isDeleted());
3043 case GraphicsContext3D::COMPILE_STATUS:
3044 m_context->getShaderiv(objectOrZero(shader), pname, &value);
3045 return WebGLGetInfo(static_cast<bool>(value));
3046 case GraphicsContext3D::SHADER_TYPE:
3047 m_context->getShaderiv(objectOrZero(shader), pname, &value);
3048 return WebGLGetInfo(static_cast<unsigned>(value));
3049 default:
3050 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
3051 return WebGLGetInfo();
3052 }
3053}
3054
3055String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
3056{
3057 UNUSED_PARAM(ec);
3058 if (isContextLostOrPending())
3059 return String();
3060 if (!validateWebGLObject("getShaderInfoLog", shader))
3061 return "";
3062 return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
3063}
3064
3065PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
3066{
3067 UNUSED_PARAM(ec);
3068 if (isContextLostOrPending())
3069 return nullptr;
3070 switch (shaderType) {
3071 case GraphicsContext3D::VERTEX_SHADER:
3072 case GraphicsContext3D::FRAGMENT_SHADER:
3073 break;
3074 default:
3075 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
3076 return nullptr;
3077 }
3078 switch (precisionType) {
3079 case GraphicsContext3D::LOW_FLOAT:
3080 case GraphicsContext3D::MEDIUM_FLOAT:
3081 case GraphicsContext3D::HIGH_FLOAT:
3082 case GraphicsContext3D::LOW_INT:
3083 case GraphicsContext3D::MEDIUM_INT:
3084 case GraphicsContext3D::HIGH_INT:
3085 break;
3086 default:
3087 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
3088 return nullptr;
3089 }
3090
3091 GC3Dint range[2] = {0, 0};
3092 GC3Dint precision = 0;
3093 m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
3094 return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
3095}
3096
3097String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
3098{
3099 UNUSED_PARAM(ec);
3100 if (isContextLostOrPending())
3101 return String();
3102 if (!validateWebGLObject("getShaderSource", shader))
3103 return "";
3104 return ensureNotNull(shader->getSource());
3105}
3106
3107Vector<String> WebGLRenderingContextBase::getSupportedExtensions()
3108{
3109 Vector<String> result;
3110
3111 if (m_isPendingPolicyResolution)
3112 return result;
3113
3114 if (m_context->getExtensions()->supports("GL_EXT_blend_minmax"))
3115 result.append("EXT_blend_minmax");
3116 if (m_context->getExtensions()->supports("GL_EXT_sRGB"))
3117 result.append("EXT_sRGB");
3118 if (m_context->getExtensions()->supports("GL_EXT_frag_depth"))
3119 result.append("EXT_frag_depth");
3120 if (m_context->getExtensions()->supports("GL_OES_texture_float"))
3121 result.append("OES_texture_float");
3122 if (m_context->getExtensions()->supports("GL_OES_texture_float_linear"))
3123 result.append("OES_texture_float_linear");
3124 if (m_context->getExtensions()->supports("GL_OES_texture_half_float"))
3125 result.append("OES_texture_half_float");
3126 if (m_context->getExtensions()->supports("GL_OES_texture_half_float_linear"))
3127 result.append("OES_texture_half_float_linear");
3128 if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
3129 result.append("OES_standard_derivatives");
3130 if (m_context->getExtensions()->supports("GL_EXT_shader_texture_lod") || m_context->getExtensions()->supports("GL_ARB_shader_texture_lod"))
3131 result.append("EXT_shader_texture_lod");
3132 if (m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic"))
3133 result.append("WEBKIT_EXT_texture_filter_anisotropic");
3134 if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
3135 result.append("OES_vertex_array_object");
3136 if (m_context->getExtensions()->supports("GL_OES_element_index_uint"))
3137 result.append("OES_element_index_uint");
3138 result.append("WEBGL_lose_context");
3139 if (WebGLCompressedTextureATC::supported(this))
3140 result.append("WEBKIT_WEBGL_compressed_texture_atc");
3141 if (WebGLCompressedTexturePVRTC::supported(this))
3142 result.append("WEBKIT_WEBGL_compressed_texture_pvrtc");
3143 if (WebGLCompressedTextureS3TC::supported(this))
3144 result.append("WEBGL_compressed_texture_s3tc");
3145 if (WebGLDepthTexture::supported(graphicsContext3D()))
3146 result.append("WEBGL_depth_texture");
3147 if (supportsDrawBuffers())
3148 result.append("WEBGL_draw_buffers");
3149 if (ANGLEInstancedArrays::supported(this))
3150 result.append("ANGLE_instanced_arrays");
3151
3152 if (allowPrivilegedExtensions()) {
3153 if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
3154 result.append("WEBGL_debug_shaders");
3155 result.append("WEBGL_debug_renderer_info");
3156 }
3157
3158 return result;
3159}
3160
3161WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
3162{
3163 UNUSED_PARAM(ec);
3164 if (isContextLostOrPending())
3165 return WebGLGetInfo();
3166 WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
3167 if (!tex)
3168 return WebGLGetInfo();
3169 GC3Dint value = 0;
3170 switch (pname) {
3171 case GraphicsContext3D::TEXTURE_MAG_FILTER:
3172 case GraphicsContext3D::TEXTURE_MIN_FILTER:
3173 case GraphicsContext3D::TEXTURE_WRAP_S:
3174 case GraphicsContext3D::TEXTURE_WRAP_T:
3175 m_context->getTexParameteriv(target, pname, &value);
3176 return WebGLGetInfo(static_cast<unsigned>(value));
3177 case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3178 if (m_extTextureFilterAnisotropic) {
3179 m_context->getTexParameteriv(target, pname, &value);
3180 return WebGLGetInfo(static_cast<unsigned>(value));
3181 }
3182 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
3183 return WebGLGetInfo();
3184 default:
3185 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
3186 return WebGLGetInfo();
3187 }
3188}
3189
3190WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
3191{
3192 UNUSED_PARAM(ec);
3193 if (isContextLostOrPending() || !validateWebGLObject("getUniform", program))
3194 return WebGLGetInfo();
3195 if (!uniformLocation || uniformLocation->program() != program) {
3196 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
3197 return WebGLGetInfo();
3198 }
3199 GC3Dint location = uniformLocation->location();
3200
3201 GC3Denum baseType;
3202 unsigned length;
3203 switch (uniformLocation->type()) {
3204 case GraphicsContext3D::BOOL:
3205 baseType = GraphicsContext3D::BOOL;
3206 length = 1;
3207 break;
3208 case GraphicsContext3D::BOOL_VEC2:
3209 baseType = GraphicsContext3D::BOOL;
3210 length = 2;
3211 break;
3212 case GraphicsContext3D::BOOL_VEC3:
3213 baseType = GraphicsContext3D::BOOL;
3214 length = 3;
3215 break;
3216 case GraphicsContext3D::BOOL_VEC4:
3217 baseType = GraphicsContext3D::BOOL;
3218 length = 4;
3219 break;
3220 case GraphicsContext3D::INT:
3221 baseType = GraphicsContext3D::INT;
3222 length = 1;
3223 break;
3224 case GraphicsContext3D::INT_VEC2:
3225 baseType = GraphicsContext3D::INT;
3226 length = 2;
3227 break;
3228 case GraphicsContext3D::INT_VEC3:
3229 baseType = GraphicsContext3D::INT;
3230 length = 3;
3231 break;
3232 case GraphicsContext3D::INT_VEC4:
3233 baseType = GraphicsContext3D::INT;
3234 length = 4;
3235 break;
3236 case GraphicsContext3D::FLOAT:
3237 baseType = GraphicsContext3D::FLOAT;
3238 length = 1;
3239 break;
3240 case GraphicsContext3D::FLOAT_VEC2:
3241 baseType = GraphicsContext3D::FLOAT;
3242 length = 2;
3243 break;
3244 case GraphicsContext3D::FLOAT_VEC3:
3245 baseType = GraphicsContext3D::FLOAT;
3246 length = 3;
3247 break;
3248 case GraphicsContext3D::FLOAT_VEC4:
3249 baseType = GraphicsContext3D::FLOAT;
3250 length = 4;
3251 break;
3252 case GraphicsContext3D::FLOAT_MAT2:
3253 baseType = GraphicsContext3D::FLOAT;
3254 length = 4;
3255 break;
3256 case GraphicsContext3D::FLOAT_MAT3:
3257 baseType = GraphicsContext3D::FLOAT;
3258 length = 9;
3259 break;
3260 case GraphicsContext3D::FLOAT_MAT4:
3261 baseType = GraphicsContext3D::FLOAT;
3262 length = 16;
3263 break;
3264 case GraphicsContext3D::SAMPLER_2D:
3265 case GraphicsContext3D::SAMPLER_CUBE:
3266 baseType = GraphicsContext3D::INT;
3267 length = 1;
3268 break;
3269 default:
3270 // Can't handle this type
3271 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
3272 return WebGLGetInfo();
3273 }
3274 switch (baseType) {
3275 case GraphicsContext3D::FLOAT: {
3276 GC3Dfloat value[16] = {0};
3277 if (m_isRobustnessEXTSupported)
3278 m_context->getExtensions()->getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
3279 else
3280 m_context->getUniformfv(objectOrZero(program), location, value);
3281 if (length == 1)
3282 return WebGLGetInfo(value[0]);
3283 return WebGLGetInfo(Float32Array::create(value, length));
3284 }
3285 case GraphicsContext3D::INT: {
3286 GC3Dint value[4] = {0};
3287 if (m_isRobustnessEXTSupported)
3288 m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
3289 else
3290 m_context->getUniformiv(objectOrZero(program), location, value);
3291 if (length == 1)
3292 return WebGLGetInfo(value[0]);
3293 return WebGLGetInfo(Int32Array::create(value, length));
3294 }
3295 case GraphicsContext3D::BOOL: {
3296 GC3Dint value[4] = {0};
3297 if (m_isRobustnessEXTSupported)
3298 m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
3299 else
3300 m_context->getUniformiv(objectOrZero(program), location, value);
3301 if (length > 1) {
3302 bool boolValue[16] = {0};
3303 for (unsigned j = 0; j < length; j++)
3304 boolValue[j] = static_cast<bool>(value[j]);
3305 return WebGLGetInfo(boolValue, length);
3306 }
3307 return WebGLGetInfo(static_cast<bool>(value[0]));
3308 }
3309 default:
3310 notImplemented();
3311 }
3312
3313 // If we get here, something went wrong in our unfortunately complex logic above
3314 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
3315 return WebGLGetInfo();
3316}
3317
3318PassRefPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
3319{
3320 UNUSED_PARAM(ec);
3321 if (isContextLostOrPending() || !validateWebGLObject("getUniformLocation", program))
3322 return nullptr;
3323 if (!validateLocationLength("getUniformLocation", name))
3324 return nullptr;
3325 if (!validateString("getUniformLocation", name))
3326 return nullptr;
3327 if (isPrefixReserved(name))
3328 return nullptr;
3329 if (!program->getLinkStatus()) {
3330 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
3331 return nullptr;
3332 }
3333 GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
3334 if (uniformLocation == -1)
3335 return nullptr;
3336
3337 GC3Dint activeUniforms = 0;
3338 m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
3339 for (GC3Dint i = 0; i < activeUniforms; i++) {
3340 ActiveInfo info;
3341 if (!m_context->getActiveUniform(objectOrZero(program), i, info))
3342 return nullptr;
3343 // Strip "[0]" from the name if it's an array.
3344 if (info.name.endsWith("[0]"))
3345 info.name = info.name.left(info.name.length() - 3);
3346 // If it's an array, we need to iterate through each element, appending "[index]" to the name.
3347 for (GC3Dint index = 0; index < info.size; ++index) {
3348 String uniformName = info.name + "[" + String::number(index) + "]";
3349
3350 if (name == uniformName || name == info.name)
3351 return WebGLUniformLocation::create(program, uniformLocation, info.type);
3352 }
3353 }
3354 return nullptr;
3355}
3356
3357WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
3358{
3359 UNUSED_PARAM(ec);
3360
3361 if (isContextLostOrPending())
3362 return WebGLGetInfo();
3363
3364 if (index >= m_maxVertexAttribs) {
3365 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
3366 return WebGLGetInfo();
3367 }
3368
3369 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3370
3371 if (m_angleInstancedArrays && pname == GraphicsContext3D::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
3372 return WebGLGetInfo(state.divisor);
3373
3374 switch (pname) {
3375 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
3376 if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
3377 || !state.bufferBinding
3378 || !state.bufferBinding->object())
3379 return WebGLGetInfo();
3380 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
3381 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
3382 return WebGLGetInfo(state.enabled);
3383 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
3384 return WebGLGetInfo(state.normalized);
3385 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
3386 return WebGLGetInfo(state.size);
3387 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
3388 return WebGLGetInfo(state.originalStride);
3389 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
3390 return WebGLGetInfo(state.type);
3391 case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
3392 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
3393 default:
3394 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
3395 return WebGLGetInfo();
3396 }
3397}
3398
3399long long WebGLRenderingContextBase::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
3400{
3401 if (isContextLostOrPending())
3402 return 0;
3403 GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
3404 return static_cast<long long>(result);
3405}
3406
3407void WebGLRenderingContextBase::hint(GC3Denum target, GC3Denum mode)
3408{
3409 if (isContextLostOrPending())
3410 return;
3411 bool isValid = false;
3412 switch (target) {
3413 case GraphicsContext3D::GENERATE_MIPMAP_HINT:
3414 isValid = true;
3415 break;
3416 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
3417 if (m_oesStandardDerivatives)
3418 isValid = true;
3419 break;
3420 }
3421 if (!isValid) {
3422 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
3423 return;
3424 }
3425 m_context->hint(target, mode);
3426}
3427
3428GC3Dboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
3429{
3430 if (!buffer || isContextLostOrPending())
3431 return 0;
3432
3433 if (!buffer->hasEverBeenBound())
3434 return 0;
3435
3436 return m_context->isBuffer(buffer->object());
3437}
3438
3439bool WebGLRenderingContextBase::isContextLost() const
3440{
3441 return m_contextLost;
3442}
3443
3444bool WebGLRenderingContextBase::isContextLostOrPending()
3445{
3446 if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution) {
3447 LOG(WebGL, "Context is being used. Attempt to resolve the policy.");
3448 Document& document = canvas()->document().topDocument();
3449 Page* page = document.page();
3450 if (page && !document.url().isLocalFile())
3451 page->mainFrame().loader().client().resolveWebGLPolicyForURL(document.url());
3452 // FIXME: We don't currently do anything with the result from resolution. A more
3453 // complete implementation might try to construct a real context, etc and proceed
3454 // with normal operation.
3455 // https://bugs.webkit.org/show_bug.cgi?id=129122
3456 m_hasRequestedPolicyResolution = true;
3457 }
3458
3459 return m_contextLost || m_isPendingPolicyResolution;
3460}
3461
3462GC3Dboolean WebGLRenderingContextBase::isEnabled(GC3Denum cap)
3463{
3464 if (isContextLostOrPending() || !validateCapability("isEnabled", cap))
3465 return 0;
3466 if (cap == GraphicsContext3D::STENCIL_TEST)
3467 return m_stencilEnabled;
3468 return m_context->isEnabled(cap);
3469}
3470
3471GC3Dboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
3472{
3473 if (!framebuffer || isContextLostOrPending())
3474 return 0;
3475
3476 if (!framebuffer->hasEverBeenBound())
3477 return 0;
3478
3479 return m_context->isFramebuffer(framebuffer->object());
3480}
3481
3482GC3Dboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
3483{
3484 if (!program || isContextLostOrPending())
3485 return 0;
3486
3487 return m_context->isProgram(program->object());
3488}
3489
3490GC3Dboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
3491{
3492 if (!renderbuffer || isContextLostOrPending())
3493 return 0;
3494
3495 if (!renderbuffer->hasEverBeenBound())
3496 return 0;
3497
3498 return m_context->isRenderbuffer(renderbuffer->object());
3499}
3500
3501GC3Dboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
3502{
3503 if (!shader || isContextLostOrPending())
3504 return 0;
3505
3506 return m_context->isShader(shader->object());
3507}
3508
3509GC3Dboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
3510{
3511 if (!texture || isContextLostOrPending())
3512 return 0;
3513
3514 if (!texture->hasEverBeenBound())
3515 return 0;
3516
3517 return m_context->isTexture(texture->object());
3518}
3519
3520void WebGLRenderingContextBase::lineWidth(GC3Dfloat width)
3521{
3522 if (isContextLostOrPending())
3523 return;
3524 m_context->lineWidth(width);
3525}
3526
3527void WebGLRenderingContextBase::linkProgram(WebGLProgram* program, ExceptionCode& ec)
3528{
3529 UNUSED_PARAM(ec);
3530 if (isContextLostOrPending() || !validateWebGLObject("linkProgram", program))
3531 return;
3532 if (!isGLES2Compliant()) {
3533 WebGLShader* vertexShader = program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER);
3534 WebGLShader* fragmentShader = program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER);
3535 if (!vertexShader || !vertexShader->isValid() || !fragmentShader || !fragmentShader->isValid() || !m_context->precisionsMatch(objectOrZero(vertexShader), objectOrZero(fragmentShader)) || !m_context->checkVaryingsPacking(objectOrZero(vertexShader), objectOrZero(fragmentShader))) {
3536 program->setLinkStatus(false);
3537 return;
3538 }
3539 }
3540
3541 m_context->linkProgram(objectOrZero(program));
3542 program->increaseLinkCount();
3543}
3544
3545void WebGLRenderingContextBase::pixelStorei(GC3Denum pname, GC3Dint param)
3546{
3547 if (isContextLostOrPending())
3548 return;
3549 switch (pname) {
3550 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
3551 m_unpackFlipY = param;
3552 break;
3553 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3554 m_unpackPremultiplyAlpha = param;
3555 break;
3556 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
3557 if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
3558 m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
3559 else {
3560 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
3561 return;
3562 }
3563 break;
3564 case GraphicsContext3D::PACK_ALIGNMENT:
3565 case GraphicsContext3D::UNPACK_ALIGNMENT:
3566 if (param == 1 || param == 2 || param == 4 || param == 8) {
3567 if (pname == GraphicsContext3D::PACK_ALIGNMENT)
3568 m_packAlignment = param;
3569 else // GraphicsContext3D::UNPACK_ALIGNMENT:
3570 m_unpackAlignment = param;
3571 m_context->pixelStorei(pname, param);
3572 } else {
3573 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
3574 return;
3575 }
3576 break;
3577 default:
3578 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
3579 return;
3580 }
3581}
3582
3583void WebGLRenderingContextBase::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
3584{
3585 if (isContextLostOrPending())
3586 return;
3587 m_context->polygonOffset(factor, units);
3588}
3589
3590void WebGLRenderingContextBase::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
3591{
3592 if (isContextLostOrPending())
3593 return;
3594 // Due to WebGL's same-origin restrictions, it is not possible to
3595 // taint the origin using the WebGL API.
3596 ASSERT(canvas()->originClean());
3597 // Validate input parameters.
3598 if (!pixels) {
3599 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
3600 return;
3601 }
3602 switch (format) {
3603 case GraphicsContext3D::ALPHA:
3604 case GraphicsContext3D::RGB:
3605 case GraphicsContext3D::RGBA:
3606 break;
3607 default:
3608 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
3609 return;
3610 }
3611 switch (type) {
3612 case GraphicsContext3D::UNSIGNED_BYTE:
3613 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3614 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3615 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3616 break;
3617 default:
3618 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
3619 return;
3620 }
3621 if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
3622 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
3623 return;
3624 }
3625 // Validate array type against pixel type.
3626 if (pixels->getType() != JSC::TypeUint8) {
3627 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
3628 return;
3629 }
3630 const char* reason = "framebuffer incomplete";
3631 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
3632 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
3633 return;
3634 }
3635 // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3636 unsigned totalBytesRequired = 0;
3637 unsigned padding = 0;
3638 if (!m_isRobustnessEXTSupported) {
3639 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3640 if (error != GraphicsContext3D::NO_ERROR) {
3641 synthesizeGLError(error, "readPixels", "invalid dimensions");
3642 return;
3643 }
3644 if (pixels->byteLength() < totalBytesRequired) {
3645 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3646 return;
3647 }
3648 }
3649
3650 clearIfComposited();
3651 void* data = pixels->baseAddress();
3652
3653 {
3654 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
3655 if (m_isRobustnessEXTSupported)
3656 m_context->getExtensions()->readnPixelsEXT(x, y, width, height, format, type, pixels->byteLength(), data);
3657 else
3658 m_context->readPixels(x, y, width, height, format, type, data);
3659 }
3660
3661#if OS(DARWIN)
3662 if (m_isRobustnessEXTSupported) // we haven't computed padding
3663 m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3664 // FIXME: remove this section when GL driver bug on Mac AND the GLES driver bug
3665 // on QC is fixed, i.e., when alpha is off, readPixels should
3666 // set alpha to 255 instead of 0.
3667 if (!m_framebufferBinding && !m_context->getContextAttributes().alpha) {
3668 unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
3669 for (GC3Dsizei iy = 0; iy < height; ++iy) {
3670 for (GC3Dsizei ix = 0; ix < width; ++ix) {
3671 pixels[3] = 255;
3672 pixels += 4;
3673 }
3674 pixels += padding;
3675 }
3676 }
3677#endif
3678}
3679
3680void WebGLRenderingContextBase::releaseShaderCompiler()
3681{
3682 if (isContextLostOrPending())
3683 return;
3684 m_context->releaseShaderCompiler();
3685}
3686
3687void WebGLRenderingContextBase::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
3688{
3689 if (isContextLostOrPending())
3690 return;
3691 if (target != GraphicsContext3D::RENDERBUFFER) {
3692 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid target");
3693 return;
3694 }
3695 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
3696 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
3697 return;
3698 }
3699 if (!validateSize("renderbufferStorage", width, height))
3700 return;
3701 switch (internalformat) {
3702 case GraphicsContext3D::DEPTH_COMPONENT16:
3703 case GraphicsContext3D::RGBA4:
3704 case GraphicsContext3D::RGB5_A1:
3705 case GraphicsContext3D::RGB565:
3706 case GraphicsContext3D::STENCIL_INDEX8:
3707 case Extensions3D::SRGB8_ALPHA8_EXT:
3708 if (internalformat == Extensions3D::SRGB8_ALPHA8_EXT && !m_extsRGB) {
3709 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
3710 return;
3711 }
3712 m_context->renderbufferStorage(target, internalformat, width, height);
3713 m_renderbufferBinding->setInternalFormat(internalformat);
3714 m_renderbufferBinding->setIsValid(true);
3715 m_renderbufferBinding->setSize(width, height);
3716 break;
3717 case GraphicsContext3D::DEPTH_STENCIL:
3718 if (isDepthStencilSupported())
3719 m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
3720 m_renderbufferBinding->setSize(width, height);
3721 m_renderbufferBinding->setIsValid(isDepthStencilSupported());
3722 m_renderbufferBinding->setInternalFormat(internalformat);
3723 break;
3724 default:
3725 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
3726 return;
3727 }
3728 applyStencilTest();
3729}
3730
3731void WebGLRenderingContextBase::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
3732{
3733 if (isContextLostOrPending())
3734 return;
3735 m_context->sampleCoverage(value, invert);
3736}
3737
3738void WebGLRenderingContextBase::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3739{
3740 if (isContextLostOrPending())
3741 return;
3742 if (!validateSize("scissor", width, height))
3743 return;
3744 m_context->scissor(x, y, width, height);
3745}
3746
3747void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
3748{
3749 UNUSED_PARAM(ec);
3750 if (isContextLostOrPending() || !validateWebGLObject("shaderSource", shader))
3751 return;
3752 String stringWithoutComments = StripComments(string).result();
3753 if (!validateString("shaderSource", stringWithoutComments))
3754 return;
3755 shader->setSource(string);
3756 m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
3757}
3758
3759void WebGLRenderingContextBase::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
3760{
3761 if (isContextLostOrPending())
3762 return;
3763 if (!validateStencilFunc("stencilFunc", func))
3764 return;
3765 m_stencilFuncRef = ref;
3766 m_stencilFuncRefBack = ref;
3767 m_stencilFuncMask = mask;
3768 m_stencilFuncMaskBack = mask;
3769 m_context->stencilFunc(func, ref, mask);
3770}
3771
3772void WebGLRenderingContextBase::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
3773{
3774 if (isContextLostOrPending())
3775 return;
3776 if (!validateStencilFunc("stencilFuncSeparate", func))
3777 return;
3778 switch (face) {
3779 case GraphicsContext3D::FRONT_AND_BACK:
3780 m_stencilFuncRef = ref;
3781 m_stencilFuncRefBack = ref;
3782 m_stencilFuncMask = mask;
3783 m_stencilFuncMaskBack = mask;
3784 break;
3785 case GraphicsContext3D::FRONT:
3786 m_stencilFuncRef = ref;
3787 m_stencilFuncMask = mask;
3788 break;
3789 case GraphicsContext3D::BACK:
3790 m_stencilFuncRefBack = ref;
3791 m_stencilFuncMaskBack = mask;
3792 break;
3793 default:
3794 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
3795 return;
3796 }
3797 m_context->stencilFuncSeparate(face, func, ref, mask);
3798}
3799
3800void WebGLRenderingContextBase::stencilMask(GC3Duint mask)
3801{
3802 if (isContextLostOrPending())
3803 return;
3804 m_stencilMask = mask;
3805 m_stencilMaskBack = mask;
3806 m_context->stencilMask(mask);
3807}
3808
3809void WebGLRenderingContextBase::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3810{
3811 if (isContextLostOrPending())
3812 return;
3813 switch (face) {
3814 case GraphicsContext3D::FRONT_AND_BACK:
3815 m_stencilMask = mask;
3816 m_stencilMaskBack = mask;
3817 break;
3818 case GraphicsContext3D::FRONT:
3819 m_stencilMask = mask;
3820 break;
3821 case GraphicsContext3D::BACK:
3822 m_stencilMaskBack = mask;
3823 break;
3824 default:
3825 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
3826 return;
3827 }
3828 m_context->stencilMaskSeparate(face, mask);
3829}
3830
3831void WebGLRenderingContextBase::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3832{
3833 if (isContextLostOrPending())
3834 return;
3835 m_context->stencilOp(fail, zfail, zpass);
3836}
3837
3838void WebGLRenderingContextBase::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3839{
3840 if (isContextLostOrPending())
3841 return;
3842 m_context->stencilOpSeparate(face, fail, zfail, zpass);
3843}
3844
3845void WebGLRenderingContextBase::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode& ec)
3846{
3847 // FIXME: For now we ignore any errors returned.
3848 ec = 0;
3849 WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3850 ASSERT(validateTexFuncParameters("texImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, format, type));
3851 ASSERT(tex);
3852 ASSERT(!level || !WebGLTexture::isNPOT(width, height));
3853 if (!pixels) {
3854 // Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
3855 // For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
3856 // can not be cleared with texImage2D and must be cleared by binding to an fbo and calling
3857 // clear.
3858 if (isResourceSafe())
3859 m_context->texImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
3860 else {
3861 bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3862 border, format, type, m_unpackAlignment);
3863 if (!succeed)
3864 return;
3865 }
3866 } else {
3867 ASSERT(validateSettableTexFormat("texImage2D", internalformat));
3868 m_context->moveErrorsToSyntheticErrorList();
3869 m_context->texImage2D(target, level, internalformat, width, height,
3870 border, format, type, pixels);
3871 if (m_context->moveErrorsToSyntheticErrorList()) {
3872 // The texImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
3873 tex->markInvalid(target, level);
3874 return;
3875 }
3876 }
3877 tex->setLevelInfo(target, level, internalformat, width, height, type);
3878}
3879
3880void WebGLRenderingContextBase::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3881{
3882 ec = 0;
3883 Vector<uint8_t> data;
3884 GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
3885 if (!imageExtractor.extractSucceeded()) {
3886 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3887 return;
3888 }
3889 GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3890 GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3891 const void* imagePixelData = imageExtractor.imagePixelData();
3892
3893 bool needConversion = true;
3894 if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
3895 needConversion = false;
3896 else {
3897 if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3898 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "packImage error");
3899 return;
3900 }
3901 }
3902
3903 if (m_unpackAlignment != 1)
3904 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3905 texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, format, type, needConversion ? data.data() : imagePixelData, ec);
3906 if (m_unpackAlignment != 1)
3907 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3908}
3909
3910bool WebGLRenderingContextBase::validateTexFunc(const char* functionName, TexFuncValidationFunctionType functionType, TexFuncValidationSourceType sourceType, GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint xoffset, GC3Dint yoffset)
3911{
3912 if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
3913 return false;
3914
3915 WebGLTexture* texture = validateTextureBinding(functionName, target, true);
3916 if (!texture)
3917 return false;
3918
3919 if (functionType == NotTexSubImage2D) {
3920 if (level && WebGLTexture::isNPOT(width, height)) {
3921 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
3922 return false;
3923 }
3924 // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
3925 // by checking if the ArrayBufferView is null or not.
3926 if (sourceType != SourceArrayBufferView) {
3927 if (!validateSettableTexFormat(functionName, format))
3928 return false;
3929 }
3930 } else {
3931 if (!validateSettableTexFormat(functionName, format))
3932 return false;
3933 if (!validateSize(functionName, xoffset, yoffset))
3934 return false;
3935 // Before checking if it is in the range, check if overflow happens first.
3936 if (xoffset + width < 0 || yoffset + height < 0) {
3937 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "bad dimensions");
3938 return false;
3939 }
3940 if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
3941 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "dimensions out of range");
3942 return false;
3943 }
3944 if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) {
3945 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type and format do not match texture");
3946 return false;
3947 }
3948 }
3949
3950 return true;
3951}
3952
3953void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3954 GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3955 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3956{
3957 if (isContextLostOrPending() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed)
3958 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
3959 return;
3960 void* data = pixels ? pixels->baseAddress() : 0;
3961 Vector<uint8_t> tempData;
3962 bool changeUnpackAlignment = false;
3963 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3964 if (!m_context->extractTextureData(width, height, format, type,
3965 m_unpackAlignment,
3966 m_unpackFlipY, m_unpackPremultiplyAlpha,
3967 data,
3968 tempData))
3969 return;
3970 data = tempData.data();
3971 changeUnpackAlignment = true;
3972 }
3973 if (changeUnpackAlignment)
3974 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3975 texImage2DBase(target, level, internalformat, width, height, border,
3976 format, type, data, ec);
3977 if (changeUnpackAlignment)
3978 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3979}
3980
3981void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3982 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3983{
3984 ec = 0;
3985 if (isContextLostOrPending() || !pixels || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
3986 return;
3987 Vector<uint8_t> data;
3988 bool needConversion = true;
3989 // The data from ImageData is always of format RGBA8.
3990 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3991 if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE)
3992 needConversion = false;
3993 else {
3994 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3995 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3996 return;
3997 }
3998 }
3999 if (m_unpackAlignment != 1)
4000 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
4001 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), ec);
4002 if (m_unpackAlignment != 1)
4003 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
4004}
4005
4006PassRefPtr<Image> WebGLRenderingContextBase::drawImageIntoBuffer(Image* image, int width, int height, int deviceScaleFactor)
4007{
4008 IntSize size(width, height);
4009 size.scale(deviceScaleFactor);
4010 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
4011 if (!buf) {
4012 synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
4013 return nullptr;
4014 }
4015
4016 FloatRect srcRect(FloatPoint(), image->size());
4017 FloatRect destRect(FloatPoint(), size);
4018 buf->context()->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect);
4019 return buf->copyImage(ImageBuffer::fastCopyImageMode());
4020}
4021
4022void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
4023 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
4024{
4025 ec = 0;
4026 if (isContextLostOrPending() || !validateHTMLImageElement("texImage2D", image, ec))
4027 return;
4028
4029 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
4030 if (imageForRender->isSVGImage())
4031 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), 1);
4032
4033 if (!imageForRender || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0))
4034 return;
4035
4036 texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
4037}
4038
4039void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
4040 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
4041{
4042 ec = 0;
4043 if (isContextLostOrPending() || !validateHTMLCanvasElement("texImage2D", canvas, ec) || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0))
4044 return;
4045
4046 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
4047 // If possible, copy from the canvas element directly to the texture
4048 // via the GPU, without a read-back to system memory.
4049 //
4050 // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE should be lifted when
4051 // ImageBuffer::copyToPlatformTexture implementations are fully functional.
4052 if (GraphicsContext3D::TEXTURE_2D == target && texture && type == texture->getType(target, level)
4053 && (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA) && type == GraphicsContext3D::UNSIGNED_BYTE) {
4054 ImageBuffer* buffer = canvas->buffer();
4055 if (buffer && buffer->copyToPlatformTexture(*m_context.get(), texture->object(), internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
4056 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
4057 return;
4058 }
4059 }
4060
4061 RefPtr<ImageData> imageData = canvas->getImageData();
4062 if (imageData)
4063 texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
4064 else
4065 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
4066}
4067
4068#if ENABLE(VIDEO)
4069PassRefPtr<Image> WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy, ExceptionCode&)
4070{
4071 IntSize size(video->videoWidth(), video->videoHeight());
4072 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
4073 if (!buf) {
4074 synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
4075 return nullptr;
4076 }
4077 IntRect destRect(0, 0, size.width(), size.height());
4078 // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
4079 video->paintCurrentFrameInContext(buf->context(), destRect);
4080 return buf->copyImage(backingStoreCopy);
4081}
4082
4083void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
4084 GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
4085{
4086 ec = 0;
4087 if (isContextLostOrPending() || !validateHTMLVideoElement("texImage2D", video, ec)
4088 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 0, format, type, 0, 0))
4089 return;
4090
4091 // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible.
4092 // Otherwise, it will fall back to the normal SW path.
4093 // FIXME: The current restrictions require that format shoud be RGB or RGBA,
4094 // type should be UNSIGNED_BYTE and level should be 0. It may be lifted in the future.
4095 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
4096 if (GraphicsContext3D::TEXTURE_2D == target && texture
4097 && (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA)
4098 && type == GraphicsContext3D::UNSIGNED_BYTE
4099 && (texture->getType(target, level) == GraphicsContext3D::UNSIGNED_BYTE || !texture->isValid(target, level))
4100 && !level) {
4101 if (video->copyVideoTextureToPlatformTexture(m_context.get(), texture->object(), level, type, internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
4102 texture->setLevelInfo(target, level, internalformat, video->videoWidth(), video->videoHeight(), type);
4103 return;
4104 }
4105 }
4106
4107 // Normal pure SW path.
4108 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode(), ec);
4109 if (!image)
4110 return;
4111 texImage2DImpl(target, level, internalformat, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
4112}
4113#endif
4114
4115void WebGLRenderingContextBase::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
4116{
4117 if (isContextLostOrPending())
4118 return;
4119 WebGLTexture* tex = validateTextureBinding("texParameter", target, false);
4120 if (!tex)
4121 return;
4122 switch (pname) {
4123 case GraphicsContext3D::TEXTURE_MIN_FILTER:
4124 case GraphicsContext3D::TEXTURE_MAG_FILTER:
4125 break;
4126 case GraphicsContext3D::TEXTURE_WRAP_S:
4127 case GraphicsContext3D::TEXTURE_WRAP_T:
4128 if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
4129 || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
4130 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter");
4131 return;
4132 }
4133 break;
4134 case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
4135 if (!m_extTextureFilterAnisotropic) {
4136 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled");
4137 return;
4138 }
4139 break;
4140 default:
4141 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "texParameter", "invalid parameter name");
4142 return;
4143 }
4144 if (isFloat) {
4145 tex->setParameterf(pname, paramf);
4146 m_context->texParameterf(target, pname, paramf);
4147 } else {
4148 tex->setParameteri(pname, parami);
4149 m_context->texParameteri(target, pname, parami);
4150 }
4151}
4152
4153void WebGLRenderingContextBase::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
4154{
4155 texParameter(target, pname, param, 0, true);
4156}
4157
4158void WebGLRenderingContextBase::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
4159{
4160 texParameter(target, pname, 0, param, false);
4161}
4162
4163void WebGLRenderingContextBase::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode& ec)
4164{
4165 // FIXME: For now we ignore any errors returned
4166 ec = 0;
4167 ASSERT(!isContextLost());
4168 ASSERT(validateTexFuncParameters("texSubImage2D", TexSubImage2D, target, level, format, width, height, 0, format, type));
4169 ASSERT(validateSize("texSubImage2D", xoffset, yoffset));
4170 ASSERT(validateSettableTexFormat("texSubImage2D", format));
4171 WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
4172 if (!tex) {
4173 ASSERT_NOT_REACHED();
4174 return;
4175 }
4176 ASSERT((xoffset + width) >= 0);
4177 ASSERT((yoffset + height) >= 0);
4178 ASSERT(tex->getWidth(target, level) >= (xoffset + width));
4179 ASSERT(tex->getHeight(target, level) >= (yoffset + height));
4180 ASSERT(tex->getInternalFormat(target, level) == format);
4181 ASSERT(tex->getType(target, level) == type);
4182 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
4183}
4184
4185void WebGLRenderingContextBase::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
4186{
4187 ec = 0;
4188 Vector<uint8_t> data;
4189 GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
4190 if (!imageExtractor.extractSucceeded()) {
4191 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image");
4192 return;
4193 }
4194 GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
4195 GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
4196 const void* imagePixelData = imageExtractor.imagePixelData();
4197
4198 bool needConversion = true;
4199 if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
4200 needConversion = false;
4201 else {
4202 if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
4203 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
4204 return;
4205 }
4206 }
4207
4208 if (m_unpackAlignment != 1)
4209 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
4210 texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(), format, type, needConversion ? data.data() : imagePixelData, ec);
4211 if (m_unpackAlignment != 1)
4212 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
4213}
4214
4215void WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
4216 GC3Dsizei width, GC3Dsizei height,
4217 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
4218{
4219 if (isContextLostOrPending() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed)
4220 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceArrayBufferView, target, level, format, width, height, 0, format, type, xoffset, yoffset))
4221 return;
4222 void* data = pixels->baseAddress();
4223 Vector<uint8_t> tempData;
4224 bool changeUnpackAlignment = false;
4225 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
4226 if (!m_context->extractTextureData(width, height, format, type,
4227 m_unpackAlignment,
4228 m_unpackFlipY, m_unpackPremultiplyAlpha,
4229 data,
4230 tempData))
4231 return;
4232 data = tempData.data();
4233 changeUnpackAlignment = true;
4234 }
4235 if (changeUnpackAlignment)
4236 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
4237 texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
4238 if (changeUnpackAlignment)
4239 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
4240}
4241
4242void WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
4243 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
4244{
4245 ec = 0;
4246 if (isContextLostOrPending() || !pixels || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageData, target, level, format, pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
4247 return;
4248
4249 Vector<uint8_t> data;
4250 bool needConversion = true;
4251 // The data from ImageData is always of format RGBA8.
4252 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
4253 if (format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
4254 needConversion = false;
4255 else {
4256 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
4257 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texSubImage2D", "bad image data");
4258 return;
4259 }
4260 }
4261 if (m_unpackAlignment != 1)
4262 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
4263 texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, type, needConversion ? data.data() : pixels->data()->data(), ec);
4264 if (m_unpackAlignment != 1)
4265 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
4266}
4267
4268void WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
4269 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
4270{
4271 ec = 0;
4272 if (isContextLostOrPending() || !validateHTMLImageElement("texSubImage2D", image, ec))
4273 return;
4274
4275 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
4276 if (imageForRender->isSVGImage())
4277 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), 1);
4278
4279 if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLImageElement, target, level, format, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset))
4280 return;
4281
4282 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
4283}
4284
4285void WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
4286 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
4287{
4288 ec = 0;
4289 if (isContextLostOrPending() || !validateHTMLCanvasElement("texSubImage2D", canvas, ec)
4290 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLCanvasElement, target, level, format, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset))
4291 return;
4292
4293 RefPtr<ImageData> imageData = canvas->getImageData();
4294 if (imageData)
4295 texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
4296 else
4297 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
4298}
4299
4300#if ENABLE(VIDEO)
4301void WebGLRenderingContextBase::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
4302 GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
4303{
4304 ec = 0;
4305 if (isContextLostOrPending() || !validateHTMLVideoElement("texSubImage2D", video, ec)
4306 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLVideoElement, target, level, format, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset))
4307 return;
4308
4309 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode(), ec);
4310 if (!image)
4311 return;
4312 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), GraphicsContext3D::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
4313}
4314#endif
4315
4316void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
4317{
4318 UNUSED_PARAM(ec);
4319 if (isContextLostOrPending() || !location)
4320 return;
4321
4322 if (location->program() != m_currentProgram) {
4323 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform1f", "location not for current program");
4324 return;
4325 }
4326
4327 m_context->uniform1f(location->location(), x);
4328}
4329
4330void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4331{
4332 UNUSED_PARAM(ec);
4333 if (isContextLostOrPending() || !validateUniformParameters("uniform1fv", location, v, 1))
4334 return;
4335
4336 m_context->uniform1fv(location->location(), v->length(), v->data());
4337}
4338
4339void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4340{
4341 UNUSED_PARAM(ec);
4342 if (isContextLostOrPending() || !validateUniformParameters("uniform1fv", location, v, size, 1))
4343 return;
4344
4345 m_context->uniform1fv(location->location(), size, v);
4346}
4347
4348void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
4349{
4350 UNUSED_PARAM(ec);
4351 if (isContextLostOrPending() || !location)
4352 return;
4353
4354 if (location->program() != m_currentProgram) {
4355 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform1i", "location not for current program");
4356 return;
4357 }
4358
4359 if ((location->type() == GraphicsContext3D::SAMPLER_2D || location->type() == GraphicsContext3D::SAMPLER_CUBE) && x >= (int)m_textureUnits.size()) {
4360 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "uniform1i", "invalid texture unit");
4361 return;
4362 }
4363
4364 m_context->uniform1i(location->location(), x);
4365}
4366
4367void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4368{
4369 UNUSED_PARAM(ec);
4370 if (isContextLostOrPending() || !validateUniformParameters("uniform1iv", location, v, 1))
4371 return;
4372
4373 if (location->type() == GraphicsContext3D::SAMPLER_2D || location->type() == GraphicsContext3D::SAMPLER_CUBE) {
4374 for (unsigned i = 0; i < v->length(); ++i) {
4375 if (v->data()[i] >= static_cast<int>(m_textureUnits.size())) {
4376 LOG(WebGL, "Texture unit size=%zu, v[%d]=%d. Location type = %04X.", m_textureUnits.size(), i, v->data()[i], location->type());
4377 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "uniform1iv", "invalid texture unit");
4378 return;
4379 }
4380 }
4381 }
4382
4383 m_context->uniform1iv(location->location(), v->length(), v->data());
4384}
4385
4386void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4387{
4388 UNUSED_PARAM(ec);
4389 if (isContextLostOrPending() || !validateUniformParameters("uniform1iv", location, v, size, 1))
4390 return;
4391
4392 if (location->type() == GraphicsContext3D::SAMPLER_2D || location->type() == GraphicsContext3D::SAMPLER_CUBE) {
4393 for (unsigned i = 0; i < static_cast<unsigned>(size); ++i) {
4394 if (((GC3Dint*)v)[i] >= static_cast<int>(m_textureUnits.size())) {
4395 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "uniform1iv", "invalid texture unit");
4396 return;
4397 }
4398 }
4399 }
4400
4401 m_context->uniform1iv(location->location(), size, v);
4402}
4403
4404void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
4405{
4406 UNUSED_PARAM(ec);
4407 if (isContextLostOrPending() || !location)
4408 return;
4409
4410 if (location->program() != m_currentProgram) {
4411 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform2f", "location not for current program");
4412 return;
4413 }
4414
4415 m_context->uniform2f(location->location(), x, y);
4416}
4417
4418void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4419{
4420 UNUSED_PARAM(ec);
4421 if (isContextLostOrPending() || !validateUniformParameters("uniform2fv", location, v, 2))
4422 return;
4423
4424 m_context->uniform2fv(location->location(), v->length() / 2, v->data());
4425}
4426
4427void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4428{
4429 UNUSED_PARAM(ec);
4430 if (isContextLostOrPending() || !validateUniformParameters("uniform2fv", location, v, size, 2))
4431 return;
4432
4433 m_context->uniform2fv(location->location(), size / 2, v);
4434}
4435
4436void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
4437{
4438 UNUSED_PARAM(ec);
4439 if (isContextLostOrPending() || !location)
4440 return;
4441
4442 if (location->program() != m_currentProgram) {
4443 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform2i", "location not for current program");
4444 return;
4445 }
4446
4447 m_context->uniform2i(location->location(), x, y);
4448}
4449
4450void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4451{
4452 UNUSED_PARAM(ec);
4453 if (isContextLostOrPending() || !validateUniformParameters("uniform2iv", location, v, 2))
4454 return;
4455
4456 m_context->uniform2iv(location->location(), v->length() / 2, v->data());
4457}
4458
4459void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4460{
4461 UNUSED_PARAM(ec);
4462 if (isContextLostOrPending() || !validateUniformParameters("uniform2iv", location, v, size, 2))
4463 return;
4464
4465 m_context->uniform2iv(location->location(), size / 2, v);
4466}
4467
4468void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
4469{
4470 UNUSED_PARAM(ec);
4471 if (isContextLostOrPending() || !location)
4472 return;
4473
4474 if (location->program() != m_currentProgram) {
4475 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform3f", "location not for current program");
4476 return;
4477 }
4478
4479 m_context->uniform3f(location->location(), x, y, z);
4480}
4481
4482void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4483{
4484 UNUSED_PARAM(ec);
4485 if (isContextLostOrPending() || !validateUniformParameters("uniform3fv", location, v, 3))
4486 return;
4487
4488 m_context->uniform3fv(location->location(), v->length() / 3, v->data());
4489}
4490
4491void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4492{
4493 UNUSED_PARAM(ec);
4494 if (isContextLostOrPending() || !validateUniformParameters("uniform3fv", location, v, size, 3))
4495 return;
4496
4497 m_context->uniform3fv(location->location(), size / 3, v);
4498}
4499
4500void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
4501{
4502 UNUSED_PARAM(ec);
4503 if (isContextLostOrPending() || !location)
4504 return;
4505
4506 if (location->program() != m_currentProgram) {
4507 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform3i", "location not for current program");
4508 return;
4509 }
4510
4511 m_context->uniform3i(location->location(), x, y, z);
4512}
4513
4514void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4515{
4516 UNUSED_PARAM(ec);
4517 if (isContextLostOrPending() || !validateUniformParameters("uniform3iv", location, v, 3))
4518 return;
4519
4520 m_context->uniform3iv(location->location(), v->length() / 3, v->data());
4521}
4522
4523void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4524{
4525 UNUSED_PARAM(ec);
4526 if (isContextLostOrPending() || !validateUniformParameters("uniform3iv", location, v, size, 3))
4527 return;
4528
4529 m_context->uniform3iv(location->location(), size / 3, v);
4530}
4531
4532void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
4533{
4534 UNUSED_PARAM(ec);
4535 if (isContextLostOrPending() || !location)
4536 return;
4537
4538 if (location->program() != m_currentProgram) {
4539 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform4f", "location not for current program");
4540 return;
4541 }
4542
4543 m_context->uniform4f(location->location(), x, y, z, w);
4544}
4545
4546void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
4547{
4548 UNUSED_PARAM(ec);
4549 if (isContextLostOrPending() || !validateUniformParameters("uniform4fv", location, v, 4))
4550 return;
4551
4552 m_context->uniform4fv(location->location(), v->length() / 4, v->data());
4553}
4554
4555void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4556{
4557 UNUSED_PARAM(ec);
4558 if (isContextLostOrPending() || !validateUniformParameters("uniform4fv", location, v, size, 4))
4559 return;
4560
4561 m_context->uniform4fv(location->location(), size / 4, v);
4562}
4563
4564void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
4565{
4566 UNUSED_PARAM(ec);
4567 if (isContextLostOrPending() || !location)
4568 return;
4569
4570 if (location->program() != m_currentProgram) {
4571 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "uniform4i", "location not for current program");
4572 return;
4573 }
4574
4575 m_context->uniform4i(location->location(), x, y, z, w);
4576}
4577
4578void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
4579{
4580 UNUSED_PARAM(ec);
4581 if (isContextLostOrPending() || !validateUniformParameters("uniform4iv", location, v, 4))
4582 return;
4583
4584 m_context->uniform4iv(location->location(), v->length() / 4, v->data());
4585}
4586
4587void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
4588{
4589 UNUSED_PARAM(ec);
4590 if (isContextLostOrPending() || !validateUniformParameters("uniform4iv", location, v, size, 4))
4591 return;
4592
4593 m_context->uniform4iv(location->location(), size / 4, v);
4594}
4595
4596void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
4597{
4598 UNUSED_PARAM(ec);
4599 if (isContextLostOrPending() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, 4))
4600 return;
4601 m_context->uniformMatrix2fv(location->location(), v->length() / 4, transpose, v->data());
4602}
4603
4604void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4605{
4606 UNUSED_PARAM(ec);
4607 if (isContextLostOrPending() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, size, 4))
4608 return;
4609 m_context->uniformMatrix2fv(location->location(), size / 4, transpose, v);
4610}
4611
4612void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
4613{
4614 UNUSED_PARAM(ec);
4615 if (isContextLostOrPending() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, 9))
4616 return;
4617 m_context->uniformMatrix3fv(location->location(), v->length() / 9, transpose, v->data());
4618}
4619
4620void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4621{
4622 UNUSED_PARAM(ec);
4623 if (isContextLostOrPending() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, size, 9))
4624 return;
4625 m_context->uniformMatrix3fv(location->location(), size / 9, transpose, v);
4626}
4627
4628void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
4629{
4630 UNUSED_PARAM(ec);
4631 if (isContextLostOrPending() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, 16))
4632 return;
4633 m_context->uniformMatrix4fv(location->location(), v->length() / 16, transpose, v->data());
4634}
4635
4636void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
4637{
4638 UNUSED_PARAM(ec);
4639 if (isContextLostOrPending() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, size, 16))
4640 return;
4641 m_context->uniformMatrix4fv(location->location(), size / 16, transpose, v);
4642}
4643
4644void WebGLRenderingContextBase::useProgram(WebGLProgram* program, ExceptionCode& ec)
4645{
4646 UNUSED_PARAM(ec);
4647 bool deleted;
4648 if (!checkObjectToBeBound("useProgram", program, deleted))
4649 return;
4650 if (deleted)
4651 program = 0;
4652 if (program && !program->getLinkStatus()) {
4653 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "useProgram", "program not valid");
4654 return;
4655 }
4656 if (m_currentProgram != program) {
4657 if (m_currentProgram)
4658 m_currentProgram->onDetached(graphicsContext3D());
4659 m_currentProgram = program;
4660 m_context->useProgram(objectOrZero(program));
4661 if (program)
4662 program->onAttached();
4663 }
4664}
4665
4666void WebGLRenderingContextBase::validateProgram(WebGLProgram* program, ExceptionCode& ec)
4667{
4668 UNUSED_PARAM(ec);
4669 if (isContextLostOrPending() || !validateWebGLObject("validateProgram", program))
4670 return;
4671 m_context->validateProgram(objectOrZero(program));
4672}
4673
4674void WebGLRenderingContextBase::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
4675{
4676 vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f);
4677}
4678
4679void WebGLRenderingContextBase::vertexAttrib1fv(GC3Duint index, Float32Array* v)
4680{
4681 vertexAttribfvImpl("vertexAttrib1fv", index, v, 1);
4682}
4683
4684void WebGLRenderingContextBase::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4685{
4686 vertexAttribfvImpl("vertexAttrib1fv", index, v, size, 1);
4687}
4688
4689void WebGLRenderingContextBase::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
4690{
4691 vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f);
4692}
4693
4694void WebGLRenderingContextBase::vertexAttrib2fv(GC3Duint index, Float32Array* v)
4695{
4696 vertexAttribfvImpl("vertexAttrib2fv", index, v, 2);
4697}
4698
4699void WebGLRenderingContextBase::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4700{
4701 vertexAttribfvImpl("vertexAttrib2fv", index, v, size, 2);
4702}
4703
4704void WebGLRenderingContextBase::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
4705{
4706 vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f);
4707}
4708
4709void WebGLRenderingContextBase::vertexAttrib3fv(GC3Duint index, Float32Array* v)
4710{
4711 vertexAttribfvImpl("vertexAttrib3fv", index, v, 3);
4712}
4713
4714void WebGLRenderingContextBase::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4715{
4716 vertexAttribfvImpl("vertexAttrib3fv", index, v, size, 3);
4717}
4718
4719void WebGLRenderingContextBase::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
4720{
4721 vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3);
4722}
4723
4724void WebGLRenderingContextBase::vertexAttrib4fv(GC3Duint index, Float32Array* v)
4725{
4726 vertexAttribfvImpl("vertexAttrib4fv", index, v, 4);
4727}
4728
4729void WebGLRenderingContextBase::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
4730{
4731 vertexAttribfvImpl("vertexAttrib4fv", index, v, size, 4);
4732}
4733
4734void WebGLRenderingContextBase::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, long long offset, ExceptionCode& ec)
4735{
4736 UNUSED_PARAM(ec);
4737 if (isContextLostOrPending())
4738 return;
4739 switch (type) {
4740 case GraphicsContext3D::BYTE:
4741 case GraphicsContext3D::UNSIGNED_BYTE:
4742 case GraphicsContext3D::SHORT:
4743 case GraphicsContext3D::UNSIGNED_SHORT:
4744 case GraphicsContext3D::FLOAT:
4745 break;
4746 default:
4747 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "vertexAttribPointer", "invalid type");
4748 return;
4749 }
4750 if (index >= m_maxVertexAttribs) {
4751 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribPointer", "index out of range");
4752 return;
4753 }
4754 if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
4755 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribPointer", "bad size, stride or offset");
4756 return;
4757 }
4758 if (!m_boundArrayBuffer) {
4759 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER");
4760 return;
4761 }
4762 // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
4763 unsigned typeSize = sizeInBytes(type);
4764 if (!typeSize) {
4765 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "vertexAttribPointer", "invalid type");
4766 return;
4767 }
4768 if ((stride % typeSize) || (static_cast<GC3Dintptr>(offset) % typeSize)) {
4769 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type");
4770 return;
4771 }
4772 GC3Dsizei bytesPerElement = size * typeSize;
4773
4774 m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GC3Dintptr>(offset), m_boundArrayBuffer);
4775 m_context->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GC3Dintptr>(offset));
4776}
4777
4778void WebGLRenderingContextBase::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
4779{
4780 if (isContextLostOrPending())
4781 return;
4782 if (!validateSize("viewport", width, height))
4783 return;
4784 m_context->viewport(x, y, width, height);
4785}
4786
4787void WebGLRenderingContextBase::forceLostContext(WebGLRenderingContextBase::LostContextMode mode)
4788{
4789 if (isContextLostOrPending()) {
4790 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "loseContext", "context already lost");
4791 return;
4792 }
4793
4794 m_contextGroup->loseContextGroup(mode);
4795}
4796
4797void WebGLRenderingContextBase::loseContextImpl(WebGLRenderingContextBase::LostContextMode mode)
4798{
4799 if (isContextLost())
4800 return;
4801
4802 m_contextLost = true;
4803 m_contextLostMode = mode;
4804
4805 if (mode == RealLostContext) {
4806 // Inform the embedder that a lost context was received. In response, the embedder might
4807 // decide to take action such as asking the user for permission to use WebGL again.
4808 if (Frame* frame = canvas()->document().frame())
4809 frame->loader().client().didLoseWebGLContext(m_context->getExtensions()->getGraphicsResetStatusARB());
4810 }
4811
4812 detachAndRemoveAllObjects();
4813
4814 if (m_drawingBuffer) {
4815 // Make absolutely sure we do not refer to an already-deleted texture or framebuffer.
4816 m_drawingBuffer->setTexture2DBinding(0);
4817 m_drawingBuffer->setFramebufferBinding(0);
4818 }
4819
4820 // There is no direct way to clear errors from a GL implementation and
4821 // looping until getError() becomes NO_ERROR might cause an infinite loop if
4822 // the driver or context implementation had a bug. So, loop a reasonably
4823 // large number of times to clear any existing errors.
4824 for (int i = 0; i < 100; ++i) {
4825 if (m_context->getError() == GraphicsContext3D::NO_ERROR)
4826 break;
4827 }
4828 ConsoleDisplayPreference display = (mode == RealLostContext) ? DisplayInConsole: DontDisplayInConsole;
4829 synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL, "loseContext", "context lost", display);
4830
4831 // Don't allow restoration unless the context lost event has both been
4832 // dispatched and its default behavior prevented.
4833 m_restoreAllowed = false;
4834
4835 // Always defer the dispatch of the context lost event, to implement
4836 // the spec behavior of queueing a task.
4837 m_dispatchContextLostEventTimer.startOneShot(0);
4838}
4839
4840void WebGLRenderingContextBase::forceRestoreContext()
4841{
4842 if (!isContextLostOrPending()) {
4843 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "restoreContext", "context not lost");
4844 return;
4845 }
4846
4847 if (!m_restoreAllowed) {
4848 if (m_contextLostMode == SyntheticLostContext)
4849 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "restoreContext", "context restoration not allowed");
4850 return;
4851 }
4852
4853 if (!m_restoreTimer.isActive())
4854 m_restoreTimer.startOneShot(0);
4855}
4856
4857PlatformLayer* WebGLRenderingContextBase::platformLayer() const
4858{
4859 return (!isContextLost() && !m_isPendingPolicyResolution) ? m_context->platformLayer() : 0;
4860}
4861
4862void WebGLRenderingContextBase::removeSharedObject(WebGLSharedObject* object)
4863{
4864 if (m_isPendingPolicyResolution)
4865 return;
4866
4867 m_contextGroup->removeObject(object);
4868}
4869
4870void WebGLRenderingContextBase::addSharedObject(WebGLSharedObject* object)
4871{
4872 if (m_isPendingPolicyResolution)
4873 return;
4874
4875 ASSERT(!isContextLost());
4876 m_contextGroup->addObject(object);
4877}
4878
4879void WebGLRenderingContextBase::removeContextObject(WebGLContextObject* object)
4880{
4881 if (m_isPendingPolicyResolution)
4882 return;
4883
4884 m_contextObjects.remove(object);
4885}
4886
4887void WebGLRenderingContextBase::addContextObject(WebGLContextObject* object)
4888{
4889 if (m_isPendingPolicyResolution)
4890 return;
4891
4892 ASSERT(!isContextLost());
4893 m_contextObjects.add(object);
4894}
4895
4896void WebGLRenderingContextBase::detachAndRemoveAllObjects()
4897{
4898 if (m_isPendingPolicyResolution)
4899 return;
4900
4901 while (m_contextObjects.size() > 0) {
4902 HashSet<WebGLContextObject*>::iterator it = m_contextObjects.begin();
4903 (*it)->detachContext();
4904 }
4905}
4906
4907bool WebGLRenderingContextBase::hasPendingActivity() const
4908{
4909 return false;
4910}
4911
4912void WebGLRenderingContextBase::stop()
4913{
4914 if (!isContextLost() && !m_isPendingPolicyResolution) {
4915 forceLostContext(SyntheticLostContext);
4916 destroyGraphicsContext3D();
4917 }
4918}
4919
4920WebGLGetInfo WebGLRenderingContextBase::getBooleanParameter(GC3Denum pname)
4921{
4922 GC3Dboolean value = 0;
4923 m_context->getBooleanv(pname, &value);
4924 return WebGLGetInfo(static_cast<bool>(value));
4925}
4926
4927WebGLGetInfo WebGLRenderingContextBase::getBooleanArrayParameter(GC3Denum pname)
4928{
4929 if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
4930 notImplemented();
4931 return WebGLGetInfo(0, 0);
4932 }
4933 GC3Dboolean value[4] = {0};
4934 m_context->getBooleanv(pname, value);
4935 bool boolValue[4];
4936 for (int ii = 0; ii < 4; ++ii)
4937 boolValue[ii] = static_cast<bool>(value[ii]);
4938 return WebGLGetInfo(boolValue, 4);
4939}
4940
4941WebGLGetInfo WebGLRenderingContextBase::getFloatParameter(GC3Denum pname)
4942{
4943 GC3Dfloat value = 0;
4944 m_context->getFloatv(pname, &value);
4945 return WebGLGetInfo(value);
4946}
4947
4948WebGLGetInfo WebGLRenderingContextBase::getIntParameter(GC3Denum pname)
4949{
4950 GC3Dint value = 0;
4951 m_context->getIntegerv(pname, &value);
4952 return WebGLGetInfo(value);
4953}
4954
4955WebGLGetInfo WebGLRenderingContextBase::getUnsignedIntParameter(GC3Denum pname)
4956{
4957 GC3Dint value = 0;
4958 m_context->getIntegerv(pname, &value);
4959 return WebGLGetInfo(static_cast<unsigned>(value));
4960}
4961
4962WebGLGetInfo WebGLRenderingContextBase::getWebGLFloatArrayParameter(GC3Denum pname)
4963{
4964 GC3Dfloat value[4] = {0};
4965 m_context->getFloatv(pname, value);
4966 unsigned length = 0;
4967 switch (pname) {
4968 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
4969 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
4970 case GraphicsContext3D::DEPTH_RANGE:
4971 length = 2;
4972 break;
4973 case GraphicsContext3D::BLEND_COLOR:
4974 case GraphicsContext3D::COLOR_CLEAR_VALUE:
4975 length = 4;
4976 break;
4977 default:
4978 notImplemented();
4979 }
4980 return WebGLGetInfo(Float32Array::create(value, length));
4981}
4982
4983WebGLGetInfo WebGLRenderingContextBase::getWebGLIntArrayParameter(GC3Denum pname)
4984{
4985 GC3Dint value[4] = {0};
4986 m_context->getIntegerv(pname, value);
4987 unsigned length = 0;
4988 switch (pname) {
4989 case GraphicsContext3D::MAX_VIEWPORT_DIMS:
4990 length = 2;
4991 break;
4992 case GraphicsContext3D::SCISSOR_BOX:
4993 case GraphicsContext3D::VIEWPORT:
4994 length = 4;
4995 break;
4996 default:
4997 notImplemented();
4998 }
4999 return WebGLGetInfo(Int32Array::create(value, length));
5000}
5001
5002void WebGLRenderingContextBase::checkTextureCompleteness(const char* functionName, bool prepareToDraw)
5003{
5004 bool resetActiveUnit = false;
5005 WebGLTexture::TextureExtensionFlag extensions = static_cast<WebGLTexture::TextureExtensionFlag>((m_oesTextureFloatLinear ? WebGLTexture::TextureExtensionFloatLinearEnabled : 0) | (m_oesTextureHalfFloatLinear ? WebGLTexture::TextureExtensionHalfFloatLinearEnabled : 0));
5006
5007 for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
5008 if ((m_textureUnits[ii].texture2DBinding && m_textureUnits[ii].texture2DBinding->needToUseBlackTexture(extensions))
5009 || (m_textureUnits[ii].textureCubeMapBinding && m_textureUnits[ii].textureCubeMapBinding->needToUseBlackTexture(extensions))) {
5010 if (ii != m_activeTextureUnit) {
5011 m_context->activeTexture(ii);
5012 resetActiveUnit = true;
5013 } else if (resetActiveUnit) {
5014 m_context->activeTexture(ii);
5015 resetActiveUnit = false;
5016 }
5017 WebGLTexture* tex2D;
5018 WebGLTexture* texCubeMap;
5019 if (prepareToDraw) {
5020 String msg(String("texture bound to texture unit ") + String::number(ii)
5021 + " is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete',"
5022 + " or it is a float/half-float type with linear filtering and without the relevant float/half-float linear extension enabled.");
5023 printGLWarningToConsole(functionName, msg.utf8().data());
5024 tex2D = m_blackTexture2D.get();
5025 texCubeMap = m_blackTextureCubeMap.get();
5026 } else {
5027 tex2D = m_textureUnits[ii].texture2DBinding.get();
5028 texCubeMap = m_textureUnits[ii].textureCubeMapBinding.get();
5029 }
5030 if (m_textureUnits[ii].texture2DBinding && m_textureUnits[ii].texture2DBinding->needToUseBlackTexture(extensions))
5031 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
5032 if (m_textureUnits[ii].textureCubeMapBinding && m_textureUnits[ii].textureCubeMapBinding->needToUseBlackTexture(extensions))
5033 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
5034 }
5035 }
5036 if (resetActiveUnit)
5037 m_context->activeTexture(m_activeTextureUnit);
5038}
5039
5040void WebGLRenderingContextBase::createFallbackBlackTextures1x1()
5041{
5042 unsigned char black[] = {0, 0, 0, 255};
5043 m_blackTexture2D = createTexture();
5044 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
5045 m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
5046 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5047 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
5048 m_blackTextureCubeMap = createTexture();
5049 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
5050 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
5051 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5052 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
5053 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5054 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
5055 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5056 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
5057 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5058 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
5059 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5060 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
5061 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
5062 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
5063}
5064
5065bool WebGLRenderingContextBase::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat, GC3Denum colorBufferFormat)
5066{
5067 unsigned need = GraphicsContext3D::getChannelBitsByFormat(texInternalFormat);
5068 unsigned have = GraphicsContext3D::getChannelBitsByFormat(colorBufferFormat);
5069 return (need & have) == need;
5070}
5071
5072GC3Denum WebGLRenderingContextBase::getBoundFramebufferColorFormat()
5073{
5074 if (m_framebufferBinding && m_framebufferBinding->object())
5075 return m_framebufferBinding->getColorBufferFormat();
5076 if (m_attributes.alpha)
5077 return GraphicsContext3D::RGBA;
5078 return GraphicsContext3D::RGB;
5079}
5080
5081int WebGLRenderingContextBase::getBoundFramebufferWidth()
5082{
5083 if (m_framebufferBinding && m_framebufferBinding->object())
5084 return m_framebufferBinding->getColorBufferWidth();
5085 return m_drawingBuffer ? m_drawingBuffer->size().width() : m_context->getInternalFramebufferSize().width();
5086}
5087
5088int WebGLRenderingContextBase::getBoundFramebufferHeight()
5089{
5090 if (m_framebufferBinding && m_framebufferBinding->object())
5091 return m_framebufferBinding->getColorBufferHeight();
5092 return m_drawingBuffer ? m_drawingBuffer->size().height() : m_context->getInternalFramebufferSize().height();
5093}
5094
5095WebGLTexture* WebGLRenderingContextBase::validateTextureBinding(const char* functionName, GC3Denum target, bool useSixEnumsForCubeMap)
5096{
5097 WebGLTexture* texture = nullptr;
5098 switch (target) {
5099 case GraphicsContext3D::TEXTURE_2D:
5100 texture = m_textureUnits[m_activeTextureUnit].texture2DBinding.get();
5101 break;
5102 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
5103 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
5104 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
5105 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
5106 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
5107 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
5108 if (!useSixEnumsForCubeMap) {
5109 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
5110 return nullptr;
5111 }
5112 texture = m_textureUnits[m_activeTextureUnit].textureCubeMapBinding.get();
5113 break;
5114 case GraphicsContext3D::TEXTURE_CUBE_MAP:
5115 if (useSixEnumsForCubeMap) {
5116 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
5117 return nullptr;
5118 }
5119 texture = m_textureUnits[m_activeTextureUnit].textureCubeMapBinding.get();
5120 break;
5121 default:
5122 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture target");
5123 return nullptr;
5124 }
5125 if (!texture)
5126 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no texture");
5127 return texture;
5128}
5129
5130bool WebGLRenderingContextBase::validateLocationLength(const char* functionName, const String& string)
5131{
5132 const unsigned maxWebGLLocationLength = 256;
5133 if (string.length() > maxWebGLLocationLength) {
5134 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "location length > 256");
5135 return false;
5136 }
5137 return true;
5138}
5139
5140bool WebGLRenderingContextBase::validateSize(const char* functionName, GC3Dint x, GC3Dint y)
5141{
5142 if (x < 0 || y < 0) {
5143 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "size < 0");
5144 return false;
5145 }
5146 return true;
5147}
5148
5149bool WebGLRenderingContextBase::validateString(const char* functionName, const String& string)
5150{
5151 for (size_t i = 0; i < string.length(); ++i) {
5152 if (!validateCharacter(string[i])) {
5153 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "string not ASCII");
5154 return false;
5155 }
5156 }
5157 return true;
5158}
5159
5160bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type, GC3Dint level)
5161{
5162 switch (format) {
5163 case GraphicsContext3D::ALPHA:
5164 case GraphicsContext3D::LUMINANCE:
5165 case GraphicsContext3D::LUMINANCE_ALPHA:
5166 case GraphicsContext3D::RGB:
5167 case GraphicsContext3D::RGBA:
5168 break;
5169 case GraphicsContext3D::DEPTH_STENCIL:
5170 case GraphicsContext3D::DEPTH_COMPONENT:
5171 if (m_webglDepthTexture)
5172 break;
5173 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "depth texture formats not enabled");
5174 return false;
5175 case Extensions3D::SRGB_EXT:
5176 case Extensions3D::SRGB_ALPHA_EXT:
5177 default:
5178 if ((format == Extensions3D::SRGB_EXT || format == Extensions3D::SRGB_ALPHA_EXT)
5179 && m_extsRGB)
5180 break;
5181 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture format");
5182 return false;
5183 }
5184
5185 switch (type) {
5186 case GraphicsContext3D::UNSIGNED_BYTE:
5187 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
5188 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
5189 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
5190 break;
5191 case GraphicsContext3D::FLOAT:
5192 if (m_oesTextureFloat)
5193 break;
5194 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
5195 return false;
5196 case GraphicsContext3D::HALF_FLOAT_OES:
5197 if (m_oesTextureHalfFloat)
5198 break;
5199 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
5200 return false;
5201 case GraphicsContext3D::UNSIGNED_INT:
5202 case GraphicsContext3D::UNSIGNED_INT_24_8:
5203 case GraphicsContext3D::UNSIGNED_SHORT:
5204 if (m_webglDepthTexture)
5205 break;
5206 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
5207 return false;
5208 default:
5209 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
5210 return false;
5211 }
5212
5213 // Verify that the combination of format and type is supported.
5214 switch (format) {
5215 case GraphicsContext3D::ALPHA:
5216 case GraphicsContext3D::LUMINANCE:
5217 case GraphicsContext3D::LUMINANCE_ALPHA:
5218 if (type != GraphicsContext3D::UNSIGNED_BYTE
5219 && type != GraphicsContext3D::FLOAT
5220 && type != GraphicsContext3D::HALF_FLOAT_OES) {
5221 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for format");
5222 return false;
5223 }
5224 break;
5225 case GraphicsContext3D::RGB:
5226 case Extensions3D::SRGB_EXT:
5227 if (type != GraphicsContext3D::UNSIGNED_BYTE
5228 && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
5229 && type != GraphicsContext3D::FLOAT
5230 && type != GraphicsContext3D::HALF_FLOAT_OES) {
5231 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGB format");
5232 return false;
5233 }
5234 break;
5235 case GraphicsContext3D::RGBA:
5236 case Extensions3D::SRGB_ALPHA_EXT:
5237 if (type != GraphicsContext3D::UNSIGNED_BYTE
5238 && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
5239 && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
5240 && type != GraphicsContext3D::FLOAT
5241 && type != GraphicsContext3D::HALF_FLOAT_OES) {
5242 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for RGBA format");
5243 return false;
5244 }
5245 break;
5246 case GraphicsContext3D::DEPTH_COMPONENT:
5247 if (!m_webglDepthTexture) {
5248 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
5249 return false;
5250 }
5251 if (type != GraphicsContext3D::UNSIGNED_SHORT
5252 && type != GraphicsContext3D::UNSIGNED_INT) {
5253 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
5254 return false;
5255 }
5256 if (level > 0) {
5257 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
5258 return false;
5259 }
5260 break;
5261 case GraphicsContext3D::DEPTH_STENCIL:
5262 if (!m_webglDepthTexture) {
5263 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled");
5264 return false;
5265 }
5266 if (type != GraphicsContext3D::UNSIGNED_INT_24_8) {
5267 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format");
5268 return false;
5269 }
5270 if (level > 0) {
5271 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format");
5272 return false;
5273 }
5274 break;
5275 default:
5276 ASSERT_NOT_REACHED();
5277 }
5278
5279 return true;
5280}
5281
5282bool WebGLRenderingContextBase::validateTexFuncLevel(const char* functionName, GC3Denum target, GC3Dint level)
5283{
5284 if (level < 0) {
5285 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level < 0");
5286 return false;
5287 }
5288 switch (target) {
5289 case GraphicsContext3D::TEXTURE_2D:
5290 if (level >= m_maxTextureLevel) {
5291 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level out of range");
5292 return false;
5293 }
5294 break;
5295 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
5296 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
5297 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
5298 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
5299 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
5300 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
5301 if (level >= m_maxCubeMapTextureLevel) {
5302 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level out of range");
5303 return false;
5304 }
5305 break;
5306 }
5307 // This function only checks if level is legal, so we return true and don't
5308 // generate INVALID_ENUM if target is illegal.
5309 return true;
5310}
5311
5312bool WebGLRenderingContextBase::validateTexFuncParameters(const char* functionName,
5313 TexFuncValidationFunctionType functionType,
5314 GC3Denum target, GC3Dint level,
5315 GC3Denum internalformat,
5316 GC3Dsizei width, GC3Dsizei height, GC3Dint border,
5317 GC3Denum format, GC3Denum type)
5318{
5319 // We absolutely have to validate the format and type combination.
5320 // The texImage2D entry points taking HTMLImage, etc. will produce
5321 // temporary data based on this combination, so it must be legal.
5322 if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level))
5323 return false;
5324
5325 if (width < 0 || height < 0) {
5326 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
5327 return false;
5328 }
5329
5330 GC3Dint maxTextureSizeForLevel = pow(2.0, m_maxTextureLevel - 1 - level);
5331 switch (target) {
5332 case GraphicsContext3D::TEXTURE_2D:
5333 if (width > maxTextureSizeForLevel || height > maxTextureSizeForLevel) {
5334 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range");
5335 return false;
5336 }
5337 break;
5338 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
5339 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
5340 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
5341 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
5342 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
5343 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
5344 if (functionType != TexSubImage2D && width != height) {
5345 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width != height for cube map");
5346 return false;
5347 }
5348 // No need to check height here. For texImage width == height.
5349 // For texSubImage that will be checked when checking yoffset + height is in range.
5350 if (width > maxTextureSizeForLevel) {
5351 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height out of range for cube map");
5352 return false;
5353 }
5354 break;
5355 default:
5356 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
5357 return false;
5358 }
5359
5360 if (format != internalformat) {
5361 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format != internalformat");
5362 return false;
5363 }
5364
5365 if (border) {
5366 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "border != 0");
5367 return false;
5368 }
5369
5370 return true;
5371}
5372
5373bool WebGLRenderingContextBase::validateTexFuncData(const char* functionName, GC3Dint level,
5374 GC3Dsizei width, GC3Dsizei height,
5375 GC3Denum format, GC3Denum type,
5376 ArrayBufferView* pixels,
5377 NullDisposition disposition)
5378{
5379 if (!pixels) {
5380 if (disposition == NullAllowed)
5381 return true;
5382 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
5383 return false;
5384 }
5385
5386 if (!validateTexFuncFormatAndType(functionName, format, type, level))
5387 return false;
5388 if (!validateSettableTexFormat(functionName, format))
5389 return false;
5390
5391 switch (type) {
5392 case GraphicsContext3D::UNSIGNED_BYTE:
5393 if (pixels->getType() != JSC::TypeUint8) {
5394 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array");
5395 return false;
5396 }
5397 break;
5398 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
5399 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
5400 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
5401 if (pixels->getType() != JSC::TypeUint16) {
5402 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
5403 return false;
5404 }
5405 break;
5406 case GraphicsContext3D::FLOAT: // OES_texture_float
5407 if (pixels->getType() != JSC::TypeFloat32) {
5408 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array");
5409 return false;
5410 }
5411 break;
5412 case GraphicsContext3D::HALF_FLOAT_OES: // OES_texture_half_float
5413 // As per the specification, ArrayBufferView should be null when
5414 // OES_texture_half_float is enabled.
5415 if (pixels) {
5416 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL");
5417 return false;
5418 }
5419 break;
5420 default:
5421 ASSERT_NOT_REACHED();
5422 }
5423
5424 unsigned totalBytesRequired;
5425 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
5426 if (error != GraphicsContext3D::NO_ERROR) {
5427 synthesizeGLError(error, functionName, "invalid texture dimensions");
5428 return false;
5429 }
5430 if (pixels->byteLength() < totalBytesRequired) {
5431 if (m_unpackAlignment != 1) {
5432 error = m_context->computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0);
5433 if (pixels->byteLength() == totalBytesRequired) {
5434 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1");
5435 return false;
5436 }
5437 }
5438 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
5439 return false;
5440 }
5441 return true;
5442}
5443
5444bool WebGLRenderingContextBase::validateCompressedTexFormat(GC3Denum format)
5445{
5446 return m_compressedTextureFormats.contains(format);
5447}
5448
5449bool WebGLRenderingContextBase::validateCompressedTexFuncData(const char* functionName,
5450 GC3Dsizei width, GC3Dsizei height,
5451 GC3Denum format, ArrayBufferView* pixels)
5452{
5453 if (!pixels) {
5454 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no pixels");
5455 return false;
5456 }
5457 if (width < 0 || height < 0) {
5458 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "width or height < 0");
5459 return false;
5460 }
5461
5462 unsigned bytesRequired = 0;
5463
5464 switch (format) {
5465 case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
5466 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
5467 case Extensions3D::COMPRESSED_ATC_RGB_AMD:
5468 {
5469 const int kBlockSize = 8;
5470 const int kBlockWidth = 4;
5471 const int kBlockHeight = 4;
5472 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
5473 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
5474 bytesRequired = numBlocksAcross * numBlocksDown * kBlockSize;
5475 }
5476 break;
5477 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
5478 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT:
5479 case Extensions3D::COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
5480 case Extensions3D::COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
5481 {
5482 const int kBlockSize = 16;
5483 const int kBlockWidth = 4;
5484 const int kBlockHeight = 4;
5485 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
5486 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
5487 bytesRequired = numBlocksAcross * numBlocksDown * kBlockSize;
5488 }
5489 break;
5490 case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
5491 case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
5492 {
5493 const int kBlockSize = 8;
5494 const int kBlockWidth = 8;
5495 const int kBlockHeight = 8;
5496 bytesRequired = (std::max(width, kBlockWidth) * std::max(height, kBlockHeight) * 4 + 7) / kBlockSize;
5497 }
5498 break;
5499 case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
5500 case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
5501 {
5502 const int kBlockSize = 8;
5503 const int kBlockWidth = 16;
5504 const int kBlockHeight = 8;
5505 bytesRequired = (std::max(width, kBlockWidth) * std::max(height, kBlockHeight) * 2 + 7) / kBlockSize;
5506 }
5507 break;
5508 default:
5509 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format");
5510 return false;
5511 }
5512
5513 if (pixels->byteLength() != bytesRequired) {
5514 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "length of ArrayBufferView is not correct for dimensions");
5515 return false;
5516 }
5517
5518 return true;
5519}
5520
5521bool WebGLRenderingContextBase::validateCompressedTexDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dsizei width, GC3Dsizei height, GC3Denum format)
5522{
5523 switch (format) {
5524 case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
5525 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
5526 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
5527 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
5528 const GC3Dsizei kBlockWidth = 4;
5529 const GC3Dsizei kBlockHeight = 4;
5530 const GC3Dint maxTextureSize = target ? m_maxTextureSize : m_maxCubeMapTextureSize;
5531 const GC3Dsizei maxCompressedDimension = maxTextureSize >> level;
5532 bool widthValid = (level && width == 1) || (level && width == 2) || (!(width % kBlockWidth) && width <= maxCompressedDimension);
5533 bool heightValid = (level && height == 1) || (level && height == 2) || (!(height % kBlockHeight) && height <= maxCompressedDimension);
5534 if (!widthValid || !heightValid) {
5535 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "width or height invalid for level");
5536 return false;
5537 }
5538 return true;
5539 }
5540 case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
5541 case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
5542 case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
5543 case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
5544 // Height and width must be powers of 2.
5545 if ((width & (width - 1)) || (height & (height - 1))) {
5546 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "width or height invalid for level");
5547 return false;
5548 }
5549 return true;
5550 default:
5551 return false;
5552 }
5553}
5554
5555bool WebGLRenderingContextBase::validateCompressedTexSubDimensions(const char* functionName, GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
5556 GC3Dsizei width, GC3Dsizei height, GC3Denum format, WebGLTexture* tex)
5557{
5558 if (xoffset < 0 || yoffset < 0) {
5559 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "xoffset or yoffset < 0");
5560 return false;
5561 }
5562
5563 switch (format) {
5564 case Extensions3D::COMPRESSED_RGB_S3TC_DXT1_EXT:
5565 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT1_EXT:
5566 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT3_EXT:
5567 case Extensions3D::COMPRESSED_RGBA_S3TC_DXT5_EXT: {
5568 const int kBlockWidth = 4;
5569 const int kBlockHeight = 4;
5570 if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
5571 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "xoffset or yoffset not multiple of 4");
5572 return false;
5573 }
5574 if (width - xoffset > tex->getWidth(target, level)
5575 || height - yoffset > tex->getHeight(target, level)) {
5576 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "dimensions out of range");
5577 return false;
5578 }
5579 return validateCompressedTexDimensions(functionName, target, level, width, height, format);
5580 }
5581 case Extensions3D::COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
5582 case Extensions3D::COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
5583 case Extensions3D::COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
5584 case Extensions3D::COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
5585 if (xoffset || yoffset) {
5586 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "xoffset and yoffset must be zero");
5587 return false;
5588 }
5589 if (width != tex->getWidth(target, level)
5590 || height != tex->getHeight(target, level)) {
5591 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "dimensions must match existing level");
5592 return false;
5593 }
5594 return validateCompressedTexDimensions(functionName, target, level, width, height, format);
5595 }
5596 default:
5597 return false;
5598 }
5599}
5600
5601bool WebGLRenderingContextBase::validateDrawMode(const char* functionName, GC3Denum mode)
5602{
5603 switch (mode) {
5604 case GraphicsContext3D::POINTS:
5605 case GraphicsContext3D::LINE_STRIP:
5606 case GraphicsContext3D::LINE_LOOP:
5607 case GraphicsContext3D::LINES:
5608 case GraphicsContext3D::TRIANGLE_STRIP:
5609 case GraphicsContext3D::TRIANGLE_FAN:
5610 case GraphicsContext3D::TRIANGLES:
5611 return true;
5612 default:
5613 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid draw mode");
5614 return false;
5615 }
5616}
5617
5618bool WebGLRenderingContextBase::validateStencilSettings(const char* functionName)
5619{
5620 if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
5621 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "front and back stencils settings do not match");
5622 return false;
5623 }
5624 return true;
5625}
5626
5627bool WebGLRenderingContextBase::validateStencilFunc(const char* functionName, GC3Denum func)
5628{
5629 switch (func) {
5630 case GraphicsContext3D::NEVER:
5631 case GraphicsContext3D::LESS:
5632 case GraphicsContext3D::LEQUAL:
5633 case GraphicsContext3D::GREATER:
5634 case GraphicsContext3D::GEQUAL:
5635 case GraphicsContext3D::EQUAL:
5636 case GraphicsContext3D::NOTEQUAL:
5637 case GraphicsContext3D::ALWAYS:
5638 return true;
5639 default:
5640 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid function");
5641 return false;
5642 }
5643}
5644
5645void WebGLRenderingContextBase::printGLErrorToConsole(const String& message)
5646{
5647 if (!m_numGLErrorsToConsoleAllowed)
5648 return;
5649
5650 --m_numGLErrorsToConsoleAllowed;
5651 printWarningToConsole(message);
5652
5653 if (!m_numGLErrorsToConsoleAllowed)
5654 printWarningToConsole("WebGL: too many errors, no more errors will be reported to the console for this context.");
5655}
5656
5657void WebGLRenderingContextBase::printWarningToConsole(const String& message)
5658{
5659 if (!canvas())
5660 return;
5661 canvas()->document().addConsoleMessage(MessageSource::Rendering, MessageLevel::Warning, message);
5662}
5663
5664bool WebGLRenderingContextBase::validateFramebufferFuncParameters(const char* functionName, GC3Denum target, GC3Denum attachment)
5665{
5666 if (target != GraphicsContext3D::FRAMEBUFFER) {
5667 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
5668 return false;
5669 }
5670 switch (attachment) {
5671 case GraphicsContext3D::COLOR_ATTACHMENT0:
5672 case GraphicsContext3D::DEPTH_ATTACHMENT:
5673 case GraphicsContext3D::STENCIL_ATTACHMENT:
5674 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
5675 break;
5676 default:
5677 if (m_webglDrawBuffers
5678 && attachment > GraphicsContext3D::COLOR_ATTACHMENT0
5679 && attachment < static_cast<GC3Denum>(GraphicsContext3D::COLOR_ATTACHMENT0 + getMaxColorAttachments()))
5680 break;
5681 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid attachment");
5682 return false;
5683 }
5684 return true;
5685}
5686
5687bool WebGLRenderingContextBase::validateBlendEquation(const char* functionName, GC3Denum mode)
5688{
5689 switch (mode) {
5690 case GraphicsContext3D::FUNC_ADD:
5691 case GraphicsContext3D::FUNC_SUBTRACT:
5692 case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
5693 case Extensions3D::MIN_EXT:
5694 case Extensions3D::MAX_EXT:
5695 if ((mode == Extensions3D::MIN_EXT || mode == Extensions3D::MAX_EXT) && !m_extBlendMinMax) {
5696 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
5697 return false;
5698 }
5699 return true;
5700 break;
5701 default:
5702 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid mode");
5703 return false;
5704 }
5705}
5706
5707bool WebGLRenderingContextBase::validateBlendFuncFactors(const char* functionName, GC3Denum src, GC3Denum dst)
5708{
5709 if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
5710 && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
5711 || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
5712 && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
5713 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "incompatible src and dst");
5714 return false;
5715 }
5716 return true;
5717}
5718
5719bool WebGLRenderingContextBase::validateCapability(const char* functionName, GC3Denum cap)
5720{
5721 switch (cap) {
5722 case GraphicsContext3D::BLEND:
5723 case GraphicsContext3D::CULL_FACE:
5724 case GraphicsContext3D::DEPTH_TEST:
5725 case GraphicsContext3D::DITHER:
5726 case GraphicsContext3D::POLYGON_OFFSET_FILL:
5727 case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
5728 case GraphicsContext3D::SAMPLE_COVERAGE:
5729 case GraphicsContext3D::SCISSOR_TEST:
5730 case GraphicsContext3D::STENCIL_TEST:
5731 return true;
5732 default:
5733 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid capability");
5734 return false;
5735 }
5736}
5737
5738bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
5739{
5740 if (!v) {
5741 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5742 return false;
5743 }
5744 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5745}
5746
5747bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
5748{
5749 if (!v) {
5750 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5751 return false;
5752 }
5753 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5754}
5755
5756bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
5757{
5758 return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize);
5759}
5760
5761bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
5762{
5763 if (!v) {
5764 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5765 return false;
5766 }
5767 return validateUniformMatrixParameters(functionName, location, transpose, v->data(), v->length(), requiredMinSize);
5768}
5769
5770bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
5771{
5772 if (!location)
5773 return false;
5774 if (location->program() != m_currentProgram) {
5775 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "location is not from current program");
5776 return false;
5777 }
5778 if (!v) {
5779 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5780 return false;
5781 }
5782 if (transpose) {
5783 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "transpose not FALSE");
5784 return false;
5785 }
5786 if (size < requiredMinSize || (size % requiredMinSize)) {
5787 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid size");
5788 return false;
5789 }
5790 return true;
5791}
5792
5793WebGLBuffer* WebGLRenderingContextBase::validateBufferDataParameters(const char* functionName, GC3Denum target, GC3Denum usage)
5794{
5795 WebGLBuffer* buffer = 0;
5796 switch (target) {
5797 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
5798 buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
5799 break;
5800 case GraphicsContext3D::ARRAY_BUFFER:
5801 buffer = m_boundArrayBuffer.get();
5802 break;
5803 default:
5804 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid target");
5805 return nullptr;
5806 }
5807 if (!buffer) {
5808 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no buffer");
5809 return nullptr;
5810 }
5811 switch (usage) {
5812 case GraphicsContext3D::STREAM_DRAW:
5813 case GraphicsContext3D::STATIC_DRAW:
5814 case GraphicsContext3D::DYNAMIC_DRAW:
5815 return buffer;
5816 }
5817 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid usage");
5818 return nullptr;
5819}
5820
5821bool WebGLRenderingContextBase::validateHTMLImageElement(const char* functionName, HTMLImageElement* image, ExceptionCode& ec)
5822{
5823 if (!image || !image->cachedImage()) {
5824 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no image");
5825 return false;
5826 }
5827 const URL& url = image->cachedImage()->response().url();
5828 if (url.isNull() || url.isEmpty() || !url.isValid()) {
5829 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid image");
5830 return false;
5831 }
5832 if (wouldTaintOrigin(image)) {
5833 ec = SECURITY_ERR;
5834 return false;
5835 }
5836 return true;
5837}
5838
5839bool WebGLRenderingContextBase::validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement* canvas, ExceptionCode& ec)
5840{
5841 if (!canvas || !canvas->buffer()) {
5842 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no canvas");
5843 return false;
5844 }
5845 if (wouldTaintOrigin(canvas)) {
5846 ec = SECURITY_ERR;
5847 return false;
5848 }
5849 return true;
5850}
5851
5852#if ENABLE(VIDEO)
5853bool WebGLRenderingContextBase::validateHTMLVideoElement(const char* functionName, HTMLVideoElement* video, ExceptionCode& ec)
5854{
5855 if (!video || !video->videoWidth() || !video->videoHeight()) {
5856 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no video");
5857 return false;
5858 }
5859 if (wouldTaintOrigin(video)) {
5860 ec = SECURITY_ERR;
5861 return false;
5862 }
5863 return true;
5864}
5865#endif
5866
5867void WebGLRenderingContextBase::vertexAttribfImpl(const char* functionName, GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
5868{
5869 if (isContextLostOrPending())
5870 return;
5871 if (index >= m_maxVertexAttribs) {
5872 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "index out of range");
5873 return;
5874 }
5875 // In GL, we skip setting vertexAttrib0 values.
5876 if (index || isGLES2Compliant()) {
5877 switch (expectedSize) {
5878 case 1:
5879 m_context->vertexAttrib1f(index, v0);
5880 break;
5881 case 2:
5882 m_context->vertexAttrib2f(index, v0, v1);
5883 break;
5884 case 3:
5885 m_context->vertexAttrib3f(index, v0, v1, v2);
5886 break;
5887 case 4:
5888 m_context->vertexAttrib4f(index, v0, v1, v2, v3);
5889 break;
5890 }
5891 }
5892 VertexAttribValue& attribValue = m_vertexAttribValue[index];
5893 attribValue.value[0] = v0;
5894 attribValue.value[1] = v1;
5895 attribValue.value[2] = v2;
5896 attribValue.value[3] = v3;
5897}
5898
5899void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
5900{
5901 if (isContextLostOrPending())
5902 return;
5903 if (!v) {
5904 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5905 return;
5906 }
5907 vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize);
5908}
5909
5910void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
5911{
5912 if (isContextLostOrPending())
5913 return;
5914 if (!v) {
5915 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no array");
5916 return;
5917 }
5918 if (size < expectedSize) {
5919 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "invalid size");
5920 return;
5921 }
5922 if (index >= m_maxVertexAttribs) {
5923 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "index out of range");
5924 return;
5925 }
5926 // In GL, we skip setting vertexAttrib0 values.
5927 if (index || isGLES2Compliant()) {
5928 switch (expectedSize) {
5929 case 1:
5930 m_context->vertexAttrib1fv(index, v);
5931 break;
5932 case 2:
5933 m_context->vertexAttrib2fv(index, v);
5934 break;
5935 case 3:
5936 m_context->vertexAttrib3fv(index, v);
5937 break;
5938 case 4:
5939 m_context->vertexAttrib4fv(index, v);
5940 break;
5941 }
5942 }
5943 VertexAttribValue& attribValue = m_vertexAttribValue[index];
5944 attribValue.initValue();
5945 for (int ii = 0; ii < expectedSize; ++ii)
5946 attribValue.value[ii] = v[ii];
5947}
5948
5949void WebGLRenderingContextBase::initVertexAttrib0()
5950{
5951 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
5952
5953 m_vertexAttrib0Buffer = createBuffer();
5954 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
5955 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
5956 m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
5957 state.bufferBinding = m_vertexAttrib0Buffer;
5958 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
5959 m_context->enableVertexAttribArray(0);
5960 m_vertexAttrib0BufferSize = 0;
5961 m_vertexAttrib0BufferValue[0] = 0.0f;
5962 m_vertexAttrib0BufferValue[1] = 0.0f;
5963 m_vertexAttrib0BufferValue[2] = 0.0f;
5964 m_vertexAttrib0BufferValue[3] = 1.0f;
5965 m_forceAttrib0BufferRefill = false;
5966 m_vertexAttrib0UsedBefore = false;
5967}
5968
5969bool WebGLRenderingContextBase::simulateVertexAttrib0(GC3Dsizei numVertex)
5970{
5971 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
5972 const VertexAttribValue& attribValue = m_vertexAttribValue[0];
5973 if (!m_currentProgram)
5974 return false;
5975 bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
5976 if (usingVertexAttrib0)
5977 m_vertexAttrib0UsedBefore = true;
5978 if (state.enabled && usingVertexAttrib0)
5979 return false;
5980 if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore)
5981 return false;
5982 m_vertexAttrib0UsedBefore = true;
5983 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
5984 GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
5985 if (bufferDataSize > m_vertexAttrib0BufferSize) {
5986 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW);
5987 m_vertexAttrib0BufferSize = bufferDataSize;
5988 m_forceAttrib0BufferRefill = true;
5989 }
5990 if (usingVertexAttrib0
5991 && (m_forceAttrib0BufferRefill
5992 || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
5993 || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
5994 || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
5995 || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
5996 auto bufferData = std::make_unique<GC3Dfloat[]>((numVertex + 1) * 4);
5997 for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
5998 bufferData[ii * 4] = attribValue.value[0];
5999 bufferData[ii * 4 + 1] = attribValue.value[1];
6000 bufferData[ii * 4 + 2] = attribValue.value[2];
6001 bufferData[ii * 4 + 3] = attribValue.value[3];
6002 }
6003 m_vertexAttrib0BufferValue[0] = attribValue.value[0];
6004 m_vertexAttrib0BufferValue[1] = attribValue.value[1];
6005 m_vertexAttrib0BufferValue[2] = attribValue.value[2];
6006 m_vertexAttrib0BufferValue[3] = attribValue.value[3];
6007 m_forceAttrib0BufferRefill = false;
6008 m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
6009 }
6010 m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
6011 return true;
6012}
6013
6014void WebGLRenderingContextBase::restoreStatesAfterVertexAttrib0Simulation()
6015{
6016 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
6017 if (state.bufferBinding != m_vertexAttrib0Buffer) {
6018 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
6019 m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
6020 }
6021 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
6022}
6023
6024void WebGLRenderingContextBase::dispatchContextLostEvent()
6025{
6026 RefPtr<WebGLContextEvent> event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "");
6027 canvas()->dispatchEvent(event);
6028 m_restoreAllowed = event->defaultPrevented();
6029 if (m_contextLostMode == RealLostContext && m_restoreAllowed)
6030 m_restoreTimer.startOneShot(0);
6031}
6032
6033void WebGLRenderingContextBase::maybeRestoreContext()
6034{
6035 ASSERT(m_contextLost);
6036 if (!m_contextLost)
6037 return;
6038
6039 // The rendering context is not restored unless the default behavior of the
6040 // webglcontextlost event was prevented earlier.
6041 //
6042 // Because of the way m_restoreTimer is set up for real vs. synthetic lost
6043 // context events, we don't have to worry about this test short-circuiting
6044 // the retry loop for real context lost events.
6045 if (!m_restoreAllowed)
6046 return;
6047
6048 int contextLostReason = m_context->getExtensions()->getGraphicsResetStatusARB();
6049
6050 switch (contextLostReason) {
6051 case GraphicsContext3D::NO_ERROR:
6052 // The GraphicsContext3D implementation might not fully
6053 // support GL_ARB_robustness semantics yet. Alternatively, the
6054 // WEBGL_lose_context extension might have been used to force
6055 // a lost context.
6056 break;
6057 case Extensions3D::GUILTY_CONTEXT_RESET_ARB:
6058 // The rendering context is not restored if this context was
6059 // guilty of causing the graphics reset.
6060 printWarningToConsole("WARNING: WebGL content on the page caused the graphics card to reset; not restoring the context");
6061 return;
6062 case Extensions3D::INNOCENT_CONTEXT_RESET_ARB:
6063 // Always allow the context to be restored.
6064 break;
6065 case Extensions3D::UNKNOWN_CONTEXT_RESET_ARB:
6066 // Warn. Ideally, prompt the user telling them that WebGL
6067 // content on the page might have caused the graphics card to
6068 // reset and ask them whether they want to continue running
6069 // the content. Only if they say "yes" should we start
6070 // attempting to restore the context.
6071 printWarningToConsole("WARNING: WebGL content on the page might have caused the graphics card to reset");
6072 break;
6073 }
6074
6075 Frame* frame = canvas()->document().frame();
6076 if (!frame)
6077 return;
6078
6079 if (!frame->loader().client().allowWebGL(frame->settings().webGLEnabled()))
6080 return;
6081
6082 FrameView* view = frame->view();
6083 if (!view)
6084 return;
6085 ScrollView* root = view->root();
6086 if (!root)
6087 return;
6088 HostWindow* hostWindow = root->hostWindow();
6089 if (!hostWindow)
6090 return;
6091
6092 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, hostWindow));
6093 if (!context) {
6094 if (m_contextLostMode == RealLostContext)
6095 m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
6096 else
6097 // This likely shouldn't happen but is the best way to report it to the WebGL app.
6098 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "", "error restoring context");
6099 return;
6100 }
6101
6102 // Construct a new drawing buffer with the new GraphicsContext3D.
6103 if (m_drawingBuffer) {
6104 m_drawingBuffer->discardResources();
6105 DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
6106 DrawingBuffer::AlphaRequirement alpha = m_attributes.alpha ? DrawingBuffer::Alpha : DrawingBuffer::Opaque;
6107 m_drawingBuffer = DrawingBuffer::create(context.get(), m_drawingBuffer->size(), preserve, alpha);
6108 m_drawingBuffer->bind();
6109 }
6110
6111 m_context = context;
6112 m_contextLost = false;
6113 setupFlags();
6114 initializeNewContext();
6115 canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
6116}
6117
6118String WebGLRenderingContextBase::ensureNotNull(const String& text) const
6119{
6120 if (text.isNull())
6121 return WTF::emptyString();
6122 return text;
6123}
6124
6125WebGLRenderingContextBase::LRUImageBufferCache::LRUImageBufferCache(int capacity)
6126 : m_buffers(std::make_unique<std::unique_ptr<ImageBuffer>[]>(capacity))
6127 , m_capacity(capacity)
6128{
6129}
6130
6131ImageBuffer* WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer(const IntSize& size)
6132{
6133 int i;
6134 for (i = 0; i < m_capacity; ++i) {
6135 ImageBuffer* buf = m_buffers[i].get();
6136 if (!buf)
6137 break;
6138 if (buf->logicalSize() != size)
6139 continue;
6140 bubbleToFront(i);
6141 return buf;
6142 }
6143
6144 std::unique_ptr<ImageBuffer> temp = ImageBuffer::create(size, 1);
6145 if (!temp)
6146 return nullptr;
6147 i = std::min(m_capacity - 1, i);
6148 m_buffers[i] = WTF::move(temp);
6149
6150 ImageBuffer* buf = m_buffers[i].get();
6151 bubbleToFront(i);
6152 return buf;
6153}
6154
6155void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx)
6156{
6157 for (int i = idx; i > 0; --i)
6158 m_buffers[i].swap(m_buffers[i-1]);
6159}
6160
6161namespace {
6162
6163 String GetErrorString(GC3Denum error)
6164 {
6165 switch (error) {
6166 case GraphicsContext3D::INVALID_ENUM:
6167 return "INVALID_ENUM";
6168 case GraphicsContext3D::INVALID_VALUE:
6169 return "INVALID_VALUE";
6170 case GraphicsContext3D::INVALID_OPERATION:
6171 return "INVALID_OPERATION";
6172 case GraphicsContext3D::OUT_OF_MEMORY:
6173 return "OUT_OF_MEMORY";
6174 case GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION:
6175 return "INVALID_FRAMEBUFFER_OPERATION";
6176 case GraphicsContext3D::CONTEXT_LOST_WEBGL:
6177 return "CONTEXT_LOST_WEBGL";
6178 default:
6179 return String::format("WebGL ERROR(%04x)", error);
6180 }
6181 }
6182
6183} // namespace anonymous
6184
6185void WebGLRenderingContextBase::synthesizeGLError(GC3Denum error, const char* functionName, const char* description, ConsoleDisplayPreference display)
6186{
6187 if (m_synthesizedErrorsToConsole && display == DisplayInConsole) {
6188 String str = String("WebGL: ") + GetErrorString(error) + ": " + String(functionName) + ": " + String(description);
6189 printGLErrorToConsole(str);
6190 }
6191 m_context->synthesizeGLError(error);
6192}
6193
6194
6195void WebGLRenderingContextBase::printGLWarningToConsole(const char* functionName, const char* description)
6196{
6197 if (m_synthesizedErrorsToConsole) {
6198 String str = String("WebGL: ") + String(functionName) + ": " + String(description);
6199 printGLErrorToConsole(str);
6200 }
6201}
6202
6203void WebGLRenderingContextBase::applyStencilTest()
6204{
6205 bool haveStencilBuffer = false;
6206
6207 if (m_framebufferBinding)
6208 haveStencilBuffer = m_framebufferBinding->hasStencilBuffer();
6209 else {
6210 RefPtr<WebGLContextAttributes> attributes = getContextAttributes();
6211 haveStencilBuffer = attributes->stencil();
6212 }
6213 enableOrDisable(GraphicsContext3D::STENCIL_TEST,
6214 m_stencilEnabled && haveStencilBuffer);
6215}
6216
6217void WebGLRenderingContextBase::enableOrDisable(GC3Denum capability, bool enable)
6218{
6219 if (enable)
6220 m_context->enable(capability);
6221 else
6222 m_context->disable(capability);
6223}
6224
6225IntSize WebGLRenderingContextBase::clampedCanvasSize()
6226{
6227 return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]),
6228 clamp(canvas()->height(), 1, m_maxViewportDims[1]));
6229}
6230
6231GC3Dint WebGLRenderingContextBase::getMaxDrawBuffers()
6232{
6233 if (!supportsDrawBuffers())
6234 return 0;
6235 if (!m_maxDrawBuffers)
6236 m_context->getIntegerv(Extensions3D::MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers);
6237 if (!m_maxColorAttachments)
6238 m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
6239 // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
6240 return std::min(m_maxDrawBuffers, m_maxColorAttachments);
6241}
6242
6243GC3Dint WebGLRenderingContextBase::getMaxColorAttachments()
6244{
6245 if (!supportsDrawBuffers())
6246 return 0;
6247 if (!m_maxColorAttachments)
6248 m_context->getIntegerv(Extensions3D::MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
6249 return m_maxColorAttachments;
6250}
6251
6252void WebGLRenderingContextBase::setBackDrawBuffer(GC3Denum buf)
6253{
6254 m_backDrawBuffer = buf;
6255}
6256
6257void WebGLRenderingContextBase::restoreCurrentFramebuffer()
6258{
6259 ExceptionCode ec;
6260 bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_framebufferBinding.get(), ec);
6261}
6262
6263void WebGLRenderingContextBase::restoreCurrentTexture2D()
6264{
6265 ExceptionCode ec;
6266 bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureUnits[m_activeTextureUnit].texture2DBinding.get(), ec);
6267}
6268
6269bool WebGLRenderingContextBase::supportsDrawBuffers()
6270{
6271 if (!m_drawBuffersWebGLRequirementsChecked) {
6272 m_drawBuffersWebGLRequirementsChecked = true;
6273 m_drawBuffersSupported = WebGLDrawBuffers::supported(this);
6274 }
6275 return m_drawBuffersSupported;
6276}
6277
6278void WebGLRenderingContextBase::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
6279{
6280 if (!primcount) {
6281 markContextChanged();
6282 return;
6283 }
6284
6285 if (!validateDrawArrays("drawArraysInstanced", mode, first, count, primcount))
6286 return;
6287
6288 clearIfComposited();
6289
6290 bool vertexAttrib0Simulated = false;
6291 if (!isGLES2Compliant())
6292 vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
6293 if (!isGLES2NPOTStrict())
6294 checkTextureCompleteness("drawArraysInstanced", true);
6295
6296 m_context->drawArraysInstanced(mode, first, count, primcount);
6297
6298 if (!isGLES2Compliant() && vertexAttrib0Simulated)
6299 restoreStatesAfterVertexAttrib0Simulation();
6300 if (!isGLES2NPOTStrict())
6301 checkTextureCompleteness("drawArraysInstanced", false);
6302 markContextChanged();
6303}
6304
6305void WebGLRenderingContextBase::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, GC3Dsizei primcount)
6306{
6307 if (!primcount) {
6308 markContextChanged();
6309 return;
6310 }
6311
6312 unsigned numElements = 0;
6313 if (!validateDrawElements("drawElementsInstanced", mode, count, type, offset, numElements, primcount))
6314 return;
6315
6316 clearIfComposited();
6317
6318 bool vertexAttrib0Simulated = false;
6319 if (!isGLES2Compliant()) {
6320 if (!numElements)
6321 validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
6322 vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
6323 }
6324 if (!isGLES2NPOTStrict())
6325 checkTextureCompleteness("drawElementsInstanced", true);
6326
6327 m_context->drawElementsInstanced(mode, count, type, static_cast<GC3Dintptr>(offset), primcount);
6328
6329 if (!isGLES2Compliant() && vertexAttrib0Simulated)
6330 restoreStatesAfterVertexAttrib0Simulation();
6331 if (!isGLES2NPOTStrict())
6332 checkTextureCompleteness("drawElementsInstanced", false);
6333 markContextChanged();
6334}
6335
6336void WebGLRenderingContextBase::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
6337{
6338 if (isContextLostOrPending())
6339 return;
6340
6341 if (index >= m_maxVertexAttribs) {
6342 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "vertexAttribDivisor", "index out of range");
6343 return;
6344 }
6345
6346 m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor);
6347 m_context->vertexAttribDivisor(index, divisor);
6348}
6349
6350
6351} // namespace WebCore
6352
6353#endif // ENABLE(WEBGL)