summaryrefslogtreecommitdiffstats
path: root/WebCore/html/canvas/WebGLRenderingContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/canvas/WebGLRenderingContext.cpp')
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.cpp201
1 files changed, 154 insertions, 47 deletions
diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp
index 7a7215d..6cb3348 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -29,8 +29,17 @@
#include "WebGLRenderingContext.h"
+#include "CanvasPixelArray.h"
+#include "HTMLCanvasElement.h"
+#include "HTMLImageElement.h"
+#include "ImageBuffer.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
+#include "RenderBox.h"
+#include "RenderLayer.h"
#include "WebGLActiveInfo.h"
#include "WebGLBuffer.h"
+#include "WebGLContextAttributes.h"
#include "WebGLFramebuffer.h"
#include "WebGLProgram.h"
#include "WebGLRenderbuffer.h"
@@ -44,6 +53,8 @@
#include "RenderBox.h"
#include "RenderLayer.h"
+#include <wtf/ByteArray.h>
+
namespace WebCore {
class WebGLStateRestorer {
@@ -65,9 +76,9 @@ private:
bool m_changed;
};
-PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas)
+PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
{
- OwnPtr<GraphicsContext3D> context(GraphicsContext3D::create());
+ OwnPtr<GraphicsContext3D> context(GraphicsContext3D::create(attrs->attributes()));
if (!context)
return 0;
@@ -574,43 +585,98 @@ void WebGLRenderingContext::disableVertexAttribArray(unsigned long index, Except
cleanupAfterGraphicsCall(false);
}
-bool WebGLRenderingContext::validateIndexArray(unsigned long count, unsigned long type, long offset, long& numElements)
+bool WebGLRenderingContext::validateElementArraySize(unsigned long count, unsigned long type, long offset)
{
- long lastIndex = -1;
if (!m_boundElementArrayBuffer)
return false;
-
+
if (offset < 0)
return false;
-
- // The GL spec says that count must be "greater
-
+
unsigned long uoffset = static_cast<unsigned long>(offset);
-
+
if (type == GraphicsContext3D::UNSIGNED_SHORT) {
// For an unsigned short array, offset must be divisible by 2 for alignment reasons.
if (uoffset & 1)
return false;
-
+
// Make uoffset an element offset.
uoffset /= 2;
-
+
unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / 2;
if (uoffset > n || count > n - uoffset)
return false;
-
- const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+ } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
+ unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
+ if (uoffset > n || count > n - uoffset)
+ return false;
+ }
+ return true;
+}
+
+bool WebGLRenderingContext::validateIndexArrayConservative(unsigned long type, long& numElementsRequired)
+{
+ // Performs conservative validation by caching a maximum index of
+ // the given type per element array buffer. If all of the bound
+ // array buffers have enough elements to satisfy that maximum
+ // index, skips the expensive per-draw-call iteration in
+ // validateIndexArrayPrecise.
+
+ long maxIndex = m_boundElementArrayBuffer->getCachedMaxIndex(type);
+ if (maxIndex < 0) {
+ // Compute the maximum index in the entire buffer for the given type of index.
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_BYTE: {
+ unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
+ const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+ for (unsigned i = 0; i < numElements; i++)
+ maxIndex = max(maxIndex, static_cast<long>(p[i]));
+ break;
+ }
+ case GraphicsContext3D::UNSIGNED_SHORT: {
+ unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / sizeof(unsigned short);
+ const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+ for (unsigned i = 0; i < numElements; i++)
+ maxIndex = max(maxIndex, static_cast<long>(p[i]));
+ break;
+ }
+ default:
+ return false;
+ }
+ m_boundElementArrayBuffer->setCachedMaxIndex(type, maxIndex);
+ }
+
+ if (maxIndex >= 0) {
+ // The number of required elements is one more than the maximum
+ // index that will be accessed.
+ numElementsRequired = maxIndex + 1;
+ return true;
+ }
+
+ return false;
+}
+
+bool WebGLRenderingContext::validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired)
+{
+ long lastIndex = -1;
+
+ if (!m_boundElementArrayBuffer)
+ return false;
+
+ unsigned long uoffset = static_cast<unsigned long>(offset);
+ unsigned long n = count;
+
+ if (type == GraphicsContext3D::UNSIGNED_SHORT) {
+ // Make uoffset an element offset.
+ uoffset /= 2;
+ const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
while (n-- > 0) {
if (*p > lastIndex)
lastIndex = *p;
++p;
}
} else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
- unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
- if (uoffset > n || count > n - uoffset)
- return false;
-
- const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+ const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
while (n-- > 0) {
if (*p > lastIndex)
lastIndex = *p;
@@ -619,11 +685,11 @@ bool WebGLRenderingContext::validateIndexArray(unsigned long count, unsigned lon
}
// Then set the last index in the index array and make sure it is valid.
- numElements = lastIndex + 1;
- return numElements > 0;
+ numElementsRequired = lastIndex + 1;
+ return numElementsRequired > 0;
}
-bool WebGLRenderingContext::validateRenderingState(long numElements)
+bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
{
// Look in each enabled vertex attrib and find the smallest buffer size
long smallestNumElements = LONG_MAX;
@@ -636,7 +702,7 @@ bool WebGLRenderingContext::validateRenderingState(long numElements)
if (smallestNumElements == LONG_MAX)
smallestNumElements = 0;
- return numElements <= smallestNumElements;
+ return numElementsRequired <= smallestNumElements;
}
void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long count, ExceptionCode& ec)
@@ -658,10 +724,16 @@ void WebGLRenderingContext::drawElements(unsigned long mode, unsigned long count
// Ensure we have a valid rendering state
long numElements;
- if (offset < 0 || !validateIndexArray(count, type, offset, numElements) || !validateRenderingState(numElements)) {
+ if (offset < 0 || !validateElementArraySize(count, type, offset)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
+
+ if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements))
+ if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
m_context->drawElements(mode, count, type, offset);
cleanupAfterGraphicsCall(true);
@@ -710,6 +782,13 @@ void WebGLRenderingContext::framebufferRenderbuffer(unsigned long target, unsign
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
+ // Don't allow the default framebuffer to be mutated; all current
+ // implementations use an FBO internally in place of the default
+ // FBO.
+ if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, buffer);
cleanupAfterGraphicsCall(false);
}
@@ -721,6 +800,13 @@ void WebGLRenderingContext::framebufferTexture2D(unsigned long target, unsigned
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
+ // Don't allow the default framebuffer to be mutated; all current
+ // implementations use an FBO internally in place of the default
+ // FBO.
+ if (!m_framebufferBinding || !m_framebufferBinding->object()) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
m_context->framebufferTexture2D(target, attachment, textarget, texture, level);
cleanupAfterGraphicsCall(false);
}
@@ -792,6 +878,13 @@ WebGLGetInfo WebGLRenderingContext::getBufferParameter(unsigned long target, uns
return WebGLGetInfo(static_cast<unsigned long>(value));
}
+PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
+{
+ // We always need to return a new WebGLContextAttributes object to
+ // prevent the user from mutating any cached version.
+ return WebGLContextAttributes::create(m_context->getContextAttributes());
+}
+
unsigned long WebGLRenderingContext::getError()
{
return m_context->getError();
@@ -1530,25 +1623,28 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned
unsigned format, unsigned type, WebGLArray* pixels, ExceptionCode& ec)
{
// FIXME: For now we ignore any errors returned
+ // FIXME: Need to make sure passed buffer has enough bytes to define the texture
ec = 0;
m_context->texImage2D(target, level, internalformat, width, height,
- border, format, type, pixels);
+ border, format, type, pixels ? pixels->baseAddress() : 0);
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
- unsigned width, unsigned height, unsigned border,
- unsigned format, unsigned type, ImageData* pixels, ExceptionCode& ec)
+void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, ImageData* pixels,
+ bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
// FIXME: For now we ignore any errors returned
+ // FIXME: Need a form of this call that can take both a pixel buffer and flipY and premultiplyAlpha flags
+ UNUSED_PARAM(flipY);
+ UNUSED_PARAM(premultiplyAlpha);
ec = 0;
- m_context->texImage2D(target, level, internalformat, width, height,
- border, format, type, pixels);
+ m_context->texImage2D(target, level, GraphicsContext3D::RGBA, pixels->width(), pixels->height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels->data()->data()->data());
+ //RLP: m_context->texImage2D(target, level, pixels, flipY, premultiplyAlpha);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLImageElement* image,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
+ bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
ec = 0;
if (!image) {
@@ -1590,9 +1686,14 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLCanv
void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video,
bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
- // FIXME: For now we ignore any errors returned
+ // FIXME: Need implement this call
+ UNUSED_PARAM(target);
+ UNUSED_PARAM(level);
+ UNUSED_PARAM(video);
+ UNUSED_PARAM(flipY);
+ UNUSED_PARAM(premultiplyAlpha);
+
ec = 0;
- m_context->texImage2D(target, level, video, flipY, premultiplyAlpha);
cleanupAfterGraphicsCall(false);
}
@@ -1613,24 +1714,26 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig
unsigned format, unsigned type, WebGLArray* pixels, ExceptionCode& ec)
{
// FIXME: For now we ignore any errors returned
+ // FIXME: Need to make sure passed buffer has enough bytes to define the texture
ec = 0;
- m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+ m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels ? pixels->baseAddress() : 0);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height,
- unsigned format, unsigned type, ImageData* pixels, ExceptionCode& ec)
+ ImageData* pixels, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
// FIXME: For now we ignore any errors returned
+ UNUSED_PARAM(flipY);
+ UNUSED_PARAM(premultiplyAlpha);
ec = 0;
- m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+ m_context->texSubImage2D(target, level, xoffset, yoffset, pixels->width(), pixels->height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels->data()->data()->data());
+ //RLP: m_context->texSubImage2D(target, level, xoffset, yoffset, pixels, flipY, premultiplyAlpha);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height, HTMLImageElement* image,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
+ HTMLImageElement* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
// FIXME: For now we ignore any errors returned
ec = 0;
@@ -1645,13 +1748,12 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig
return;
}
- m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, cachedImage->image(), flipY, premultiplyAlpha);
+ m_context->texSubImage2D(target, level, xoffset, yoffset, cachedImage->image(), flipY, premultiplyAlpha);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height, HTMLCanvasElement* canvas,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
+ HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
ec = 0;
if (!canvas) {
@@ -1666,17 +1768,22 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig
}
// FIXME: For now we ignore any errors returned
- m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, buffer->image(), flipY, premultiplyAlpha);
+ m_context->texSubImage2D(target, level, xoffset, yoffset, buffer->image(), flipY, premultiplyAlpha);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- unsigned width, unsigned height, HTMLVideoElement* video,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- // FIXME: For now we ignore any errors returned
+ HTMLVideoElement* video, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
+{
+ // FIXME: Need to implement this call
+ UNUSED_PARAM(target);
+ UNUSED_PARAM(level);
+ UNUSED_PARAM(xoffset);
+ UNUSED_PARAM(yoffset);
+ UNUSED_PARAM(video);
+ UNUSED_PARAM(flipY);
+ UNUSED_PARAM(premultiplyAlpha);
ec = 0;
- m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, video, flipY, premultiplyAlpha);
cleanupAfterGraphicsCall(false);
}