diff options
Diffstat (limited to 'Source/WebCore/platform')
23 files changed, 3312 insertions, 28 deletions
diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp index 9e64904..43819b6 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.cpp @@ -20,7 +20,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -57,20 +57,20 @@ void ANGLEWebKitBridge::cleanupCompilers() builtCompilers = false; } - + void ANGLEWebKitBridge::setResources(ShBuiltInResources resources) { // Resources are (possibly) changing - cleanup compilers if we had them already cleanupCompilers(); - + m_resources = resources; } bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog) { if (!builtCompilers) { - m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_WEBGL_SPEC, &m_resources); - m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_WEBGL_SPEC, &m_resources); + m_fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_WEBGL_SPEC, SH_GLSL_OUTPUT, &m_resources); + m_vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_WEBGL_SPEC, SH_GLSL_OUTPUT, &m_resources); if (!m_fragmentCompiler || !m_vertexCompiler) { cleanupCompilers(); return false; @@ -78,7 +78,7 @@ bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShad builtCompilers = true; } - + ShHandle compiler; if (shaderType == SHADER_TYPE_VERTEX) diff --git a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h index a9d2238..e8008a7 100644 --- a/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h +++ b/Source/WebCore/platform/graphics/ANGLEWebKitBridge.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2011, Sony Ericsson Mobile Communications AB * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,7 +30,7 @@ #include "PlatformString.h" #include <wtf/text/CString.h> -#if !PLATFORM(GTK) +#if !PLATFORM(GTK) && !PLATFORM(ANDROID) #include "ANGLE/ShaderLang.h" #else #include "ShaderLang.h" diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.cpp b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp index 324fed8..03bcd9e 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -21,7 +21,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -56,10 +56,13 @@ namespace { } // anonymous namespace - PassRefPtr<DrawingBuffer> GraphicsContext3D::createDrawingBuffer(const IntSize& size) { - return DrawingBuffer::create(this, size); +#if ENABLE(ACCELERATED_2D_CANVAS) + return DrawingBuffer::create(this, size); +#else + return 0; +#endif } bool GraphicsContext3D::texImage2DResourceSafe(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint unpackAlignment) diff --git a/Source/WebCore/platform/graphics/GraphicsContext3D.h b/Source/WebCore/platform/graphics/GraphicsContext3D.h index 80226cf..b2a4d3a 100644 --- a/Source/WebCore/platform/graphics/GraphicsContext3D.h +++ b/Source/WebCore/platform/graphics/GraphicsContext3D.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2011, Sony Ericsson Mobile Communications AB * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -88,6 +89,9 @@ class Extensions3D; class Extensions3DOpenGL; #endif class HostWindow; +#if PLATFORM(ANDROID) +class HTMLCanvasElement; +#endif class Image; class ImageData; #if USE(CAIRO) @@ -101,7 +105,7 @@ struct ActiveInfo { }; // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) +#if PLATFORM(ANDROID) || PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) class GraphicsContext3DInternal; #endif @@ -452,7 +456,12 @@ public: void setContextLostCallback(PassOwnPtr<ContextLostCallback>); +#if PLATFORM(ANDROID) + static PassRefPtr<GraphicsContext3D> create(HTMLCanvasElement*, Attributes, + HostWindow*, RenderStyle = RenderOffscreen); +#else static PassRefPtr<GraphicsContext3D> create(Attributes, HostWindow*, RenderStyle = RenderOffscreen); +#endif ~GraphicsContext3D(); #if PLATFORM(MAC) @@ -474,6 +483,12 @@ public: #elif PLATFORM(GTK) PlatformGraphicsContext3D platformGraphicsContext3D(); Platform3DObject platformTexture() const { return m_texture; } +#elif PLATFORM(ANDROID) + PlatformGraphicsContext3D platformGraphicsContext3D(); + Platform3DObject platformTexture() const; +#if USE(ACCELERATED_COMPOSITING) + PlatformLayer* platformLayer() const; +#endif #else PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } Platform3DObject platformTexture() const { return NullPlatform3DObject; } @@ -770,12 +785,18 @@ public: int canvasWidth, int canvasHeight, PlatformContextCairo* context); #endif +#if PLATFORM(ANDROID) + void recreateSurface(); + void releaseSurface(); +#endif + void markContextChanged(); void markLayerComposited(); bool layerComposited() const; void paintRenderingResultsToCanvas(CanvasRenderingContext* context); PassRefPtr<ImageData> paintRenderingResultsToImageData(); + bool paintCompositedResultsToCanvas(CanvasRenderingContext* context); #if PLATFORM(QT) bool paintsIntoCanvasBuffer() const { return true; } @@ -821,7 +842,12 @@ public: IntSize getInternalFramebufferSize(); private: +#if PLATFORM(ANDROID) + GraphicsContext3D(HTMLCanvasElement* canvas, Attributes attrs, + HostWindow* hostWindow, bool renderDirectlyToHostWindow); +#else GraphicsContext3D(Attributes attrs, HostWindow* hostWindow, bool renderDirectlyToHostWindow); +#endif // Each platform must provide an implementation of this method. // @@ -929,7 +955,7 @@ public: #endif // FIXME: ideally this would be used on all platforms. -#if PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) +#if PLATFORM(ANDROID) || PLATFORM(CHROMIUM) || PLATFORM(QT) || PLATFORM(GTK) friend class GraphicsContext3DInternal; OwnPtr<GraphicsContext3DInternal> m_internal; #endif diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h index c184bbe..fa546e3 100644 --- a/Source/WebCore/platform/graphics/ImageBuffer.h +++ b/Source/WebCore/platform/graphics/ImageBuffer.h @@ -33,6 +33,7 @@ #include "FloatRect.h" #include "GraphicsTypes.h" #include "IntSize.h" +#include "ImageBuffer.h" #include "ImageBufferData.h" #include <wtf/ByteArray.h> #include <wtf/Forward.h> @@ -77,9 +78,9 @@ namespace WebCore { const IntSize& size() const { return m_size; } int width() const { return m_size.width(); } int height() const { return m_size.height(); } - + size_t dataSize() const; - + GraphicsContext* context() const; bool isAccelerated() const { return m_accelerateRendering; } @@ -91,7 +92,7 @@ namespace WebCore { void putUnmultipliedImageData(ByteArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint); void putPremultipliedImageData(ByteArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint); - + String toDataURL(const String& mimeType, const double* quality = 0) const; #if !USE(CG) AffineTransform baseTransform() const { return AffineTransform(); } @@ -129,7 +130,7 @@ namespace WebCore { ImageBuffer(const IntSize&, ColorSpace colorSpace, RenderingMode renderingMode, bool& success); }; -#if USE(CG) || USE(SKIA) +#if USE(CG) || USE(SKIA) || PLATFORM(ANDROID) String ImageDataToDataURL(const ImageData& input, const String& mimeType, const double* quality); #endif diff --git a/Source/WebCore/platform/graphics/android/Extensions3DAndroid.cpp b/Source/WebCore/platform/graphics/android/Extensions3DAndroid.cpp new file mode 100644 index 0000000..36fbe15 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/Extensions3DAndroid.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2011, Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Sony Ericsson Mobile Communications AB nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL SONY ERICSSON MOBILE COMMUNICATIONS AB BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEBGL) + +#include "Extensions3DAndroid.h" +#include "GraphicsContext3D.h" + +#include <GLES2/gl2.h> + +namespace WebCore { + +Extensions3DAndroid::Extensions3DAndroid(const String& extensions) + : m_extensions(extensions) +{ +} + +Extensions3DAndroid::~Extensions3DAndroid() +{ +} + +bool Extensions3DAndroid::supports(const String& ext) +{ + return m_extensions.contains(ext); +} + +void Extensions3DAndroid::ensureEnabled(const String& name) +{ +} + +bool Extensions3DAndroid::isEnabled(const String& name) +{ + return supports(name); +} + +int Extensions3DAndroid::getGraphicsResetStatusARB() +{ + return GraphicsContext3D::NO_ERROR; +} + +void Extensions3DAndroid::blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, + long dstX0, long dstY0, long dstX1, long dstY1, + unsigned long mask, unsigned long filter) +{ +} + +void Extensions3DAndroid::renderbufferStorageMultisample(unsigned long target, + unsigned long samples, + unsigned long internalformat, + unsigned long width, + unsigned long height) +{ +} + +Platform3DObject Extensions3DAndroid::createVertexArrayOES() +{ + return 0; +} + +void Extensions3DAndroid::deleteVertexArrayOES(Platform3DObject) +{ +} + +GC3Dboolean Extensions3DAndroid::isVertexArrayOES(Platform3DObject) +{ + return GL_FALSE; +} + +void Extensions3DAndroid::bindVertexArrayOES(Platform3DObject) +{ +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/android/Extensions3DAndroid.h b/Source/WebCore/platform/graphics/android/Extensions3DAndroid.h new file mode 100644 index 0000000..ff50fa8 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/Extensions3DAndroid.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011, Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Sony Ericsson Mobile Communications AB nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL SONY ERICSSON MOBILE COMMUNICATIONS AB BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Extensions3DAndroid_h +#define Extensions3DAndroid_h + +#include "Extensions3D.h" +#include "PlatformString.h" + +namespace WebCore { + +class Extensions3DAndroid : public Extensions3D { +public: + Extensions3DAndroid(const String& extensions); + virtual ~Extensions3DAndroid(); + + // Extensions3D methods. + virtual bool supports(const String&); + virtual void ensureEnabled(const String&); + virtual bool isEnabled(const String&); + virtual int getGraphicsResetStatusARB(); + virtual void blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, + long dstX0, long dstY0, long dstX1, long dstY1, + unsigned long mask, unsigned long filter); + virtual void renderbufferStorageMultisample(unsigned long target, unsigned long samples, + unsigned long internalformat, unsigned long width, + unsigned long height); + virtual Platform3DObject createVertexArrayOES(); + virtual void deleteVertexArrayOES(Platform3DObject); + virtual GC3Dboolean isVertexArrayOES(Platform3DObject); + virtual void bindVertexArrayOES(Platform3DObject); + +private: + String m_extensions; +}; + +} // namespace WebCore + +#endif // Extensions3DAndroid_h diff --git a/Source/WebCore/platform/graphics/android/GraphicsContext3DAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContext3DAndroid.cpp new file mode 100644 index 0000000..df706a2 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GraphicsContext3DAndroid.cpp @@ -0,0 +1,1368 @@ +/* + * Copyright (C) 2011, 2012, Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Sony Ericsson Mobile Communications AB nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL SONY ERICSSON MOBILE COMMUNICATIONS AB BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEBGL) +#include "BitmapImage.h" +#include "text/CString.h" +#include "GraphicsContext3D.h" +#include "GraphicsContext3DInternal.h" +#include "Image.h" +#include "ImageData.h" +#include "ImageDecoder.h" +#include "SkBitmap.h" +#include "SkBitmapRef.h" + +namespace WebCore { + + +PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(HTMLCanvasElement* canvas, Attributes attrs, + HostWindow *win, RenderStyle style) +{ + GraphicsContext3D *context = new GraphicsContext3D(canvas, attrs, win, false); + if (!context->m_internal->isValid()) { + // Something failed during initialization + delete context; + return 0; + } + return adoptRef(context); +} + +GraphicsContext3D::GraphicsContext3D(HTMLCanvasElement* canvas, Attributes attrs, + HostWindow* hostWindow, bool renderDirectlyToHostWindow) + : m_internal(new GraphicsContext3DInternal(canvas, attrs, hostWindow)) +{ + LOGWEBGL("GraphicsContext3D() = %p", this); + m_currentWidth = m_internal->width(); + m_currentHeight = m_internal->height(); +} + +GraphicsContext3D::~GraphicsContext3D() +{ + LOGWEBGL("~GraphicsContext3D()"); +} + +PlatformLayer* GraphicsContext3D::platformLayer() const +{ + return m_internal->platformLayer(); +} + +void GraphicsContext3D::makeContextCurrent() { + m_internal->makeContextCurrent(); +} + +bool GraphicsContext3D::isGLES2Compliant() const +{ + return true; +} + +void GraphicsContext3D::synthesizeGLError(GC3Denum error) +{ + m_internal->synthesizeGLError(error); +} + +Extensions3D* GraphicsContext3D::getExtensions() +{ + return m_internal->getExtensions(); +} + +void GraphicsContext3D::paintRenderingResultsToCanvas(CanvasRenderingContext* context) +{ + makeContextCurrent(); + m_internal->paintRenderingResultsToCanvas(context); +} + +PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData() +{ + makeContextCurrent(); + return m_internal->paintRenderingResultsToImageData(); +} + +bool GraphicsContext3D::paintCompositedResultsToCanvas(CanvasRenderingContext* context) +{ + makeContextCurrent(); + return m_internal->paintCompositedResultsToCanvas(context); +} + +bool GraphicsContext3D::getImageData(Image* image, + unsigned int format, + unsigned int type, + bool premultiplyAlpha, + bool ignoreGammaAndColorProfile, + Vector<uint8_t>& outputVector) +{ + LOGWEBGL("getImageData(%p, %u, %u, %s, %s)", image, format, type, + premultiplyAlpha ? "true" : "false", ignoreGammaAndColorProfile ? "true" : "false"); + if (!image) + return false; + + AlphaOp neededAlphaOp = AlphaDoNothing; + bool hasAlpha = (image->data() && image->isBitmapImage()) ? + static_cast<BitmapImage*>(image)->frameHasAlphaAtIndex(0) : true; + ImageDecoder* decoder = 0; + ImageFrame* buf = 0; + + if ((ignoreGammaAndColorProfile || (hasAlpha && !premultiplyAlpha)) && image->data()) { + // Attempt to get raw unpremultiplied image data + decoder = ImageDecoder::create(*(image->data()), + premultiplyAlpha ? + ImageSource::AlphaPremultiplied : + ImageSource::AlphaNotPremultiplied, + ignoreGammaAndColorProfile ? + ImageSource::GammaAndColorProfileIgnored : + ImageSource::GammaAndColorProfileApplied); + if (decoder) { + decoder->setData(image->data(), true); + buf = decoder->frameBufferAtIndex(0); + if (buf && buf->hasAlpha() && premultiplyAlpha) + neededAlphaOp = AlphaDoPremultiply; + } + } + + SkBitmapRef* bitmapRef = 0; + if (!buf) { + bitmapRef = image->nativeImageForCurrentFrame(); + if (!bitmapRef) + return false; + if (!premultiplyAlpha && hasAlpha) + neededAlphaOp = AlphaDoUnmultiply; + } + + SkBitmap& bitmap = buf ? buf->bitmap() : bitmapRef->bitmap(); + unsigned char* pixels = 0; + int rowBytes = 0; + uint32_t* tmpPixels = 0; + + int width = bitmap.width(); + int height = bitmap.height(); + int iwidth = image->width(); + int iheight = image->height(); + LOGWEBGL(" bitmap.width() = %d, image->width() = %d, bitmap.height = %d, image->height() = %d", + width, iwidth, height, iheight); + if (width != iwidth || height != iheight) { + // This image has probably been subsampled because it was too big. + // Currently, we cannot handle this in WebGL: give up. + return false; + } + SkBitmap::Config skiaConfig = bitmap.getConfig(); + + bitmap.lockPixels(); + if (skiaConfig == SkBitmap::kARGB_8888_Config) { + LOGWEBGL(" skiaConfig = kARGB_8888_Config"); + pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels()); + rowBytes = bitmap.rowBytes(); + if (!pixels) { + bitmap.unlockPixels(); + return false; + } + } + else if (skiaConfig == SkBitmap::kIndex8_Config) { + LOGWEBGL(" skiaConfig = kIndex8_Config"); + rowBytes = width * 4; + tmpPixels = (uint32_t*)fastMalloc(width * height * 4); + if (!tmpPixels) { + bitmap.unlockPixels(); + return false; + } + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + SkPMColor c = bitmap.getIndex8Color(j, i); + tmpPixels[i * width + j] = c;//SkExpand_8888(c); + } + } + pixels = (unsigned char*)tmpPixels; + } + + outputVector.resize(rowBytes * height); + LOGWEBGL("rowBytes() = %d, width() = %d, height() = %d", rowBytes, width, height); + + bool res = packPixels(pixels, + SourceFormatRGBA8, width, height, 0, + format, type, neededAlphaOp, outputVector.data()); + bitmap.unlockPixels(); + + if (decoder) + delete decoder; + + if (tmpPixels) + fastFree(tmpPixels); + + return res; +} + +unsigned GraphicsContext3D::createBuffer() +{ + LOGWEBGL("glCreateBuffer()"); + makeContextCurrent(); + GLuint b = 0; + glGenBuffers(1, &b); + return b; +} + +unsigned GraphicsContext3D::createFramebuffer() +{ + LOGWEBGL("glCreateFramebuffer()"); + makeContextCurrent(); + GLuint fb = 0; + glGenFramebuffers(1, &fb); + return fb; +} + +unsigned GraphicsContext3D::createProgram() +{ + LOGWEBGL("glCreateProgram()"); + makeContextCurrent(); + return glCreateProgram(); +} + +unsigned GraphicsContext3D::createRenderbuffer() +{ + LOGWEBGL("glCreateRenderbuffer()"); + makeContextCurrent(); + GLuint rb = 0; + glGenRenderbuffers(1, &rb); + return rb; +} + +unsigned GraphicsContext3D::createShader(GC3Denum type) +{ + LOGWEBGL("glCreateShader()"); + makeContextCurrent(); + return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); +} + +unsigned GraphicsContext3D::createTexture() +{ + LOGWEBGL("glCreateTexture()"); + makeContextCurrent(); + GLuint t = 0; + glGenTextures(1, &t); + return t; +} + +void GraphicsContext3D::deleteBuffer(unsigned buffer) +{ + LOGWEBGL("glDeleteBuffers()"); + makeContextCurrent(); + glDeleteBuffers(1, &buffer); +} + +void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer) +{ + LOGWEBGL("glDeleteFramebuffers()"); + makeContextCurrent(); + glDeleteFramebuffers(1, &framebuffer); +} + +void GraphicsContext3D::deleteProgram(unsigned program) +{ + LOGWEBGL("glDeleteProgram()"); + makeContextCurrent(); + glDeleteProgram(program); +} + +void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer) +{ + LOGWEBGL("glDeleteRenderbuffers()"); + makeContextCurrent(); + glDeleteRenderbuffers(1, &renderbuffer); +} + +void GraphicsContext3D::deleteShader(unsigned shader) +{ + LOGWEBGL("glDeleteShader()"); + makeContextCurrent(); + glDeleteShader(shader); +} + +void GraphicsContext3D::deleteTexture(unsigned texture) +{ + LOGWEBGL("glDeleteTextures()"); + makeContextCurrent(); + glDeleteTextures(1, &texture); +} + + +void GraphicsContext3D::activeTexture(GC3Denum texture) +{ + LOGWEBGL("glActiveTexture(%ld)", texture); + makeContextCurrent(); + glActiveTexture(texture); +} + +void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader) +{ + LOGWEBGL("glAttachShader(%d, %d)", program, shader); + makeContextCurrent(); + glAttachShader(program, shader); +} + +void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, + const String& name) +{ + CString cs = name.utf8(); + LOGWEBGL("glBindAttribLocation(%d, %d, %s)", program, index, cs.data()); + if (!program) + return; + makeContextCurrent(); + glBindAttribLocation(program, index, cs.data()); +} + +void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer) +{ + LOGWEBGL("glBindBuffer(%d, %d)", target, buffer); + makeContextCurrent(); + glBindBuffer(target, buffer); +} + +void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject framebuffer) +{ + LOGWEBGL("bindFrameBuffer(%d, %d)", target, framebuffer); + m_internal->bindFramebuffer(target, framebuffer); +} + +void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject renderbuffer) +{ + LOGWEBGL("glBindRenderBuffer(%d, %d)", target, renderbuffer); + makeContextCurrent(); + glBindRenderbuffer(target, renderbuffer); +} + +void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) +{ + LOGWEBGL("glBindTexture(%d, %d)", target, texture); + makeContextCurrent(); + glBindTexture(target, texture); +} + +void GraphicsContext3D::blendColor(GC3Dclampf red, GC3Dclampf green, + GC3Dclampf blue, GC3Dclampf alpha) +{ + LOGWEBGL("glBlendColor(%lf, %lf, %lf, %lf)", red, green, blue, alpha); + makeContextCurrent(); + glBlendColor(CLAMP(red), CLAMP(green), CLAMP(blue), CLAMP(alpha)); +} + +void GraphicsContext3D::blendEquation(GC3Denum mode) +{ + LOGWEBGL("glBlendEquation(%d)", mode); + makeContextCurrent(); + glBlendEquation(mode); +} + +void GraphicsContext3D::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha) +{ + LOGWEBGL("glBlendEquationSeparate(%d, %d)", modeRGB, modeAlpha); + makeContextCurrent(); + glBlendEquationSeparate(modeRGB, modeAlpha); +} + +void GraphicsContext3D::blendFunc(GC3Denum sfactor, GC3Denum dfactor) +{ + LOGWEBGL("glBlendFunc(%d, %d)", sfactor, dfactor); + makeContextCurrent(); + glBlendFunc(sfactor, dfactor); +} + +void GraphicsContext3D::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, + GC3Denum srcAlpha, GC3Denum dstAlpha) +{ + LOGWEBGL("glBlendFuncSeparate(%lu, %lu, %lu, %lu)", srcRGB, dstRGB, srcAlpha, dstAlpha); + makeContextCurrent(); + glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage) +{ + LOGWEBGL("glBufferData(%lu, %d, %lu)", target, size, usage); + makeContextCurrent(); + glBufferData(target, size, 0, usage); +} + +void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, + const void* data, GC3Denum usage) +{ + LOGWEBGL("glBufferData(%lu, %d, %p, %lu)", target, size, data, usage); + makeContextCurrent(); + glBufferData(target, size, data, usage); +} + +void GraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, + GC3Dsizeiptr size, const void* data) +{ + LOGWEBGL("glBufferSubData(%lu, %ld, %d, %p)", target, offset, size, data); + makeContextCurrent(); + glBufferSubData(target, offset, size, data); +} + +GC3Denum GraphicsContext3D::checkFramebufferStatus(GC3Denum target) +{ + LOGWEBGL("glCheckFramebufferStatus(%lu)", target); + makeContextCurrent(); + return glCheckFramebufferStatus(target); +} + +void GraphicsContext3D::clear(GC3Dbitfield mask) +{ + LOGWEBGL("glClear(%lu)", mask); + makeContextCurrent(); + glClear(mask); +} + +void GraphicsContext3D::clearColor(GC3Dclampf red, GC3Dclampf green, + GC3Dclampf blue, GC3Dclampf alpha) +{ + LOGWEBGL("glClearColor(%.2lf, %.2lf, %.2lf, %.2lf)", red, green, blue, alpha); + makeContextCurrent(); + glClearColor(CLAMP(red), CLAMP(green), CLAMP(blue), CLAMP(alpha)); +} + +void GraphicsContext3D::clearDepth(GC3Dclampf depth) +{ + LOGWEBGL("glClearDepthf(%.2lf)", depth); + makeContextCurrent(); + glClearDepthf(CLAMP(depth)); +} + +void GraphicsContext3D::clearStencil(GC3Dint s) +{ + LOGWEBGL("glClearStencil(%ld)", s); + makeContextCurrent(); + glClearStencil(s); +} + +void GraphicsContext3D::colorMask(GC3Dboolean red, GC3Dboolean green, + GC3Dboolean blue, GC3Dboolean alpha) +{ + LOGWEBGL("glColorMask(%s, %s, %s, %s)", red ? "true" : "false", green ? "true" : "false", + blue ? "true" : "false", alpha ? "true" : "false"); + makeContextCurrent(); + glColorMask(red, green, blue, alpha); +} + +void GraphicsContext3D::compileShader(Platform3DObject shader) +{ + LOGWEBGL("compileShader(%lu)", shader); + makeContextCurrent(); + m_internal->compileShader(shader); +} + +void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, + GC3Dint x, GC3Dint y, GC3Dsizei width, + GC3Dsizei height, GC3Dint border) +{ + LOGWEBGL("glCopyTexImage2D(%lu, %ld, %lu, %ld, %ld, %lu, %lu, %ld", + target, level, internalformat, x, y, width, height, border); + makeContextCurrent(); + glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); +} + +void GraphicsContext3D::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, + GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, + GC3Dsizei height) +{ + LOGWEBGL("glCopyTexSubImage2D(%lu, %ld, %ld, %ld, %ld, %ld, %lu, %lu)", + target, level, xoffset, yoffset, x, y, width, height); + makeContextCurrent(); + glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +} + +void GraphicsContext3D::cullFace(GC3Denum mode) +{ + LOGWEBGL("glCullFace(%lu)", mode); + makeContextCurrent(); + glCullFace(mode); +} + +void GraphicsContext3D::depthFunc(GC3Denum func) +{ + LOGWEBGL("glDepthFunc(%lu)", func); + makeContextCurrent(); + glDepthFunc(func); +} + +void GraphicsContext3D::depthMask(GC3Dboolean flag) +{ + LOGWEBGL("glDepthMask(%s)", flag ? "true" : "false"); + makeContextCurrent(); + glDepthMask(flag); +} + +void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar) +{ + LOGWEBGL("glDepthRangef(%.2lf, %.2lf)", zNear, zFar); + makeContextCurrent(); + glDepthRangef(CLAMP(zNear), CLAMP(zFar)); +} + +void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader) +{ + LOGWEBGL("glDetachShader(%lu, %lu)", program, shader); + makeContextCurrent(); + glDetachShader(program, shader); +} + +void GraphicsContext3D::disable(GC3Denum cap) +{ + LOGWEBGL("glDisable(%lu)", cap); + makeContextCurrent(); + glDisable(cap); +} + +void GraphicsContext3D::disableVertexAttribArray(GC3Duint index) +{ + LOGWEBGL("glDisableVertexAttribArray(%lu)", index); + makeContextCurrent(); + glDisableVertexAttribArray(index); +} + +void GraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count) +{ + LOGWEBGL("glDrawArrays(%lu, %ld, %ld)", mode, first, count); + makeContextCurrent(); + glDrawArrays(mode, first, count); +} + +void GraphicsContext3D::drawElements(GC3Denum mode, GC3Dsizei count, + GC3Denum type, GC3Dintptr offset) +{ + LOGWEBGL("glDrawElements(%lu, %lu, %lu, %ld)", mode, count, type, offset); + makeContextCurrent(); + glDrawElements(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::enable(GC3Denum cap) +{ + LOGWEBGL("glEnable(0x%04x)", cap); + makeContextCurrent(); + glEnable(cap); +} + +void GraphicsContext3D::enableVertexAttribArray(GC3Duint index) +{ + LOGWEBGL("glEnableVertexAttribArray(%lu)", index); + makeContextCurrent(); + glEnableVertexAttribArray(index); +} + +void GraphicsContext3D::finish() +{ + LOGWEBGL("glFinish()"); + makeContextCurrent(); + glFinish(); +} + +void GraphicsContext3D::flush() +{ + LOGWEBGL("glFlush()"); + makeContextCurrent(); + glFlush(); +} + +void GraphicsContext3D::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, + GC3Denum renderbuffertarget, + Platform3DObject renderbuffer) +{ + LOGWEBGL("glFramebufferRenderbuffer(%lu, %lu, %lu, %lu)", target, attachment, + renderbuffertarget, renderbuffer); + makeContextCurrent(); + glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); +} + +void GraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, + GC3Denum textarget, Platform3DObject texture, + GC3Dint level) +{ + LOGWEBGL("glFramebufferTexture2D(%lu, %lu, %lu, %lu, %ld)", + target, attachment, textarget, texture, level); + makeContextCurrent(); + glFramebufferTexture2D(target, attachment, textarget, texture, level); +} + +void GraphicsContext3D::frontFace(GC3Denum mode) +{ + LOGWEBGL("glFrontFace(%lu)", mode); + makeContextCurrent(); + glFrontFace(mode); +} + +void GraphicsContext3D::generateMipmap(GC3Denum target) +{ + LOGWEBGL("glGenerateMipmap(%lu)", target); + makeContextCurrent(); + glGenerateMipmap(target); +} + +bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info) +{ + LOGWEBGL("glGetActiveAttrib(%lu, %lu)", program, index); + if (!program) { + synthesizeGLError(INVALID_VALUE); + return false; + } + makeContextCurrent(); + GLint maxAttributeSize = 0; + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); + GLchar name[maxAttributeSize]; + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveAttrib(program, index, maxAttributeSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + +bool GraphicsContext3D::getActiveUniform(Platform3DObject program, GC3Duint index, ActiveInfo& info) +{ + LOGWEBGL("glGetActiveUniform(%lu, %lu)", program, index); + if (!program) { + synthesizeGLError(INVALID_VALUE); + return false; + } + makeContextCurrent(); + GLint maxUniformSize = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize); + GLchar name[maxUniformSize]; + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(program, index, maxUniformSize, &nameLength, &size, &type, name); + if (!nameLength) + return false; + info.name = String(name, nameLength); + info.type = type; + info.size = size; + return true; +} + +void GraphicsContext3D::getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, + GC3Dsizei* count, Platform3DObject* shaders) +{ + LOGWEBGL("glGetAttachedShaders(%lu, %d, %p, %p)", program, maxCount, count, shaders); + if (!program) { + synthesizeGLError(INVALID_VALUE); + return; + } + makeContextCurrent(); + glGetAttachedShaders(program, maxCount, count, shaders); +} + +GC3Dint GraphicsContext3D::getAttribLocation(Platform3DObject program, const String& name) +{ + CString cs = name.utf8(); + LOGWEBGL("glGetAttribLocation(%lu, %s)", program, cs.data()); + if (!program) { + return -1; + } + makeContextCurrent(); + + return glGetAttribLocation(program, cs.data()); +} + +void GraphicsContext3D::getBooleanv(GC3Denum pname, GC3Dboolean* value) +{ + LOGWEBGL("glGetBooleanv(%lu, %p)", pname, value); + makeContextCurrent(); + glGetBooleanv(pname, value); +} + +void GraphicsContext3D::getBufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetBufferParameteriv(%lu, %lu, %p)", target, pname, value); + makeContextCurrent(); + glGetBufferParameteriv(target, pname, value); +} + +GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes() +{ + LOGWEBGL("getContextAttributes()"); + return m_internal->getContextAttributes(); +} + +GC3Denum GraphicsContext3D::getError() +{ + LOGWEBGL("getError()"); + return m_internal->getError(); +} + +void GraphicsContext3D::getFloatv(GC3Denum pname, GC3Dfloat* value) +{ + LOGWEBGL("glGetFloatv(%lu, %p)", pname, value); + makeContextCurrent(); + glGetFloatv(pname, value); +} + +void GraphicsContext3D::getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, + GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetFramebufferAttachmentParameteriv(%lu, %lu, %lu, %p)", + target, attachment, pname, value); + makeContextCurrent(); + if (attachment == DEPTH_STENCIL_ATTACHMENT) + attachment = DEPTH_ATTACHMENT; + glGetFramebufferAttachmentParameteriv(target, attachment, pname, value); +} + +void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetIntegerv(%lu, %p)", pname, value); + makeContextCurrent(); + glGetIntegerv(pname, value); +} + +void GraphicsContext3D::getProgramiv(Platform3DObject program, GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetProgramiv(%lu, %lu, %p)", program, pname, value); + makeContextCurrent(); + glGetProgramiv(program, pname, value); +} + +String GraphicsContext3D::getProgramInfoLog(Platform3DObject program) +{ + LOGWEBGL("glGetProgramInfoLog(%lu)", program); + makeContextCurrent(); + GLint length; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); + if (!length) + return ""; + + GLsizei size; + GLchar* info = (GLchar*)fastMalloc(length); + glGetProgramInfoLog(program, length, &size, info); + String s(info); + fastFree(info); + + return s; +} + +void GraphicsContext3D::getRenderbufferParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetRenderbufferParameteriv(%lu, %lu, %p)", target, pname, value); + makeContextCurrent(); + glGetRenderbufferParameteriv(target, pname, value); +} + +void GraphicsContext3D::getShaderiv(Platform3DObject shader, GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetShaderiv(%lu, %lu, %p)", shader, pname, value); + makeContextCurrent(); + glGetShaderiv(shader, pname, value); +} + +String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader) +{ + LOGWEBGL("getShaderInfoLog(%lu)", shader); + makeContextCurrent(); + return m_internal->getShaderInfoLog(shader); +} + +String GraphicsContext3D::getShaderSource(Platform3DObject shader) +{ + LOGWEBGL("getShaderSource(%lu)", shader); + makeContextCurrent(); + return m_internal->getShaderSource(shader); +} + +String GraphicsContext3D::getString(GC3Denum name) +{ + LOGWEBGL("glGetString(%lu)", name); + makeContextCurrent(); + return String(reinterpret_cast<const char*>(glGetString(name))); +} + +void GraphicsContext3D::getTexParameterfv(GC3Denum target, GC3Denum pname, GC3Dfloat* value) +{ + LOGWEBGL("glGetTexParameterfv(%lu, %lu, %p)", target, pname, value); + makeContextCurrent(); + glGetTexParameterfv(target, pname, value); +} + +void GraphicsContext3D::getTexParameteriv(GC3Denum target, GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetTexParameteriv(%lu, %lu, %p)", target, pname, value); + makeContextCurrent(); + glGetTexParameteriv(target, pname, value); +} + +void GraphicsContext3D::getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value) +{ + LOGWEBGL("glGetUniformfv(%lu, %ld, %p)", program, location, value); + makeContextCurrent(); + glGetUniformfv(program, location, value); +} + +void GraphicsContext3D::getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value) +{ + LOGWEBGL("glGetUniformiv(%lu, %ld, %p)", program, location, value); + makeContextCurrent(); + glGetUniformiv(program, location, value); +} + +GC3Dint GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name) +{ + CString cs = name.utf8(); + LOGWEBGL("glGetUniformLocation(%lu, %s)", program, cs.data()); + makeContextCurrent(); + return glGetUniformLocation(program, cs.data()); +} + +void GraphicsContext3D::getVertexAttribfv(GC3Duint index, GC3Denum pname, GC3Dfloat* value) +{ + LOGWEBGL("glGetVertexAttribfv(%lu, %lu, %p)", index, pname, value); + makeContextCurrent(); + glGetVertexAttribfv(index, pname, value); +} + +void GraphicsContext3D::getVertexAttribiv(GC3Duint index, GC3Denum pname, GC3Dint* value) +{ + LOGWEBGL("glGetVertexAttribiv(%lu, %lu, %p)", index, pname, value); + makeContextCurrent(); + glGetVertexAttribiv(index, pname, value); +} + +GC3Dsizeiptr GraphicsContext3D::getVertexAttribOffset(GC3Duint index, GC3Denum pname) +{ + LOGWEBGL("glGetVertexAttribOffset(%lu, %lu)", index, pname); + GLvoid* pointer = 0; + glGetVertexAttribPointerv(index, pname, &pointer); + return static_cast<GC3Dsizeiptr>(reinterpret_cast<intptr_t>(pointer)); +} + +void GraphicsContext3D::hint(GC3Denum target, GC3Denum mode) +{ + LOGWEBGL("glHint(%lu, %lu)", target, mode); + makeContextCurrent(); + glHint(target, mode); +} + +GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer) +{ + LOGWEBGL("glIsBuffer(%lu)", buffer); + if (!buffer) + return GL_FALSE; + makeContextCurrent(); + return glIsBuffer(buffer); +} + +GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap) +{ + LOGWEBGL("glIsEnabled(%lu)", cap); + makeContextCurrent(); + return glIsEnabled(cap); +} + +GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer) +{ + LOGWEBGL("glIsFramebuffer(%lu)", framebuffer); + if (!framebuffer) + return GL_FALSE; + makeContextCurrent(); + return glIsFramebuffer(framebuffer); +} + +GC3Dboolean GraphicsContext3D::isProgram(Platform3DObject program) +{ + LOGWEBGL("glIsProgram(%lu)", program); + if (!program) + return GL_FALSE; + makeContextCurrent(); + return glIsProgram(program); +} + +GC3Dboolean GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer) +{ + LOGWEBGL("glIsRenderbuffer(%lu)", renderbuffer); + if (!renderbuffer) + return GL_FALSE; + makeContextCurrent(); + return glIsRenderbuffer(renderbuffer); +} + +GC3Dboolean GraphicsContext3D::isShader(Platform3DObject shader) +{ + LOGWEBGL("glIsShader(%lu)", shader); + if (!shader) + return GL_FALSE; + makeContextCurrent(); + return glIsShader(shader); +} + +GC3Dboolean GraphicsContext3D::isTexture(Platform3DObject texture) +{ + LOGWEBGL("glIsTexture(%lu)", texture); + if (!texture) + return GL_FALSE; + makeContextCurrent(); + return glIsTexture(texture); +} + +void GraphicsContext3D::lineWidth(GC3Dfloat width) +{ + LOGWEBGL("glLineWidth(%.2lf)", width); + makeContextCurrent(); + glLineWidth((GLfloat)width); +} + +void GraphicsContext3D::linkProgram(Platform3DObject program) +{ + LOGWEBGL("glLinkProgram(%lu)", program); + makeContextCurrent(); + glLinkProgram(program); +} + +void GraphicsContext3D::pixelStorei(GC3Denum pname, GC3Dint param) +{ + LOGWEBGL("glPixelStorei(%lu, %ld)", pname, param); + makeContextCurrent(); + glPixelStorei(pname, param); +} + +void GraphicsContext3D::polygonOffset(GC3Dfloat factor, GC3Dfloat units) +{ + LOGWEBGL("glPolygonOffset(%.2lf, %.2lf)", factor, units); + makeContextCurrent(); + glPolygonOffset((GLfloat)factor, (GLfloat)units); +} + +void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, + GC3Denum format, GC3Denum type, void* data) +{ + LOGWEBGL("glReadPixels(%ld, %ld, %lu, %lu, %lu, %lu, %p)", + x, y, width, height, format, type, data); + makeContextCurrent(); + glReadPixels(x, y, width, height, format, type, data); +} + +void GraphicsContext3D::releaseShaderCompiler() +{ + LOGWEBGL("glReleaseShaderCompiler()"); + makeContextCurrent(); + glReleaseShaderCompiler(); +} + +void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, + GC3Dsizei width, GC3Dsizei height) +{ + LOGWEBGL("glRenderbufferStorage(%lu, %lu, %lu, %lu)", + target, internalformat, width, height); + makeContextCurrent(); + glRenderbufferStorage(target, internalformat, width, height); +} + +void GraphicsContext3D::sampleCoverage(GC3Dclampf value, GC3Dboolean invert) +{ + LOGWEBGL("glSampleCoverage(%.2lf, %s)", value, invert ? "true" : "false"); + makeContextCurrent(); + glSampleCoverage(CLAMP(value), invert); +} + +void GraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) +{ + LOGWEBGL("glScissor(%ld, %ld, %lu, %lu)", x, y, width, height); + makeContextCurrent(); + glScissor(x, y, width, height); +} + +void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& source) +{ + LOGWEBGL("shaderSource(%lu, %s)", shader, source.utf8().data()); + makeContextCurrent(); + m_internal->shaderSource(shader, source); +} + +void GraphicsContext3D::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask) +{ + LOGWEBGL("glStencilFunc(%lu, %ld, %lu)", func, ref, mask); + makeContextCurrent(); + glStencilFunc(func, ref, mask); +} + +void GraphicsContext3D::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask) +{ + LOGWEBGL("glStencilFuncSeparate(%lu, %lu, %ld, %lu)", face, func, ref, mask); + makeContextCurrent(); + glStencilFuncSeparate(face, func, ref, mask); +} + +void GraphicsContext3D::stencilMask(GC3Duint mask) +{ + LOGWEBGL("glStencilMask(%lu)", mask); + makeContextCurrent(); + glStencilMask(mask); +} + +void GraphicsContext3D::stencilMaskSeparate(GC3Denum face, GC3Duint mask) +{ + LOGWEBGL("glStencilMaskSeparate(%lu, %lu)", face, mask); + makeContextCurrent(); + glStencilMaskSeparate(face, mask); +} + +void GraphicsContext3D::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass) +{ + LOGWEBGL("glStencilOp(%lu, %lu, %lu)", fail, zfail, zpass); + makeContextCurrent(); + glStencilOp(fail, zfail, zpass); +} + +void GraphicsContext3D::stencilOpSeparate(GC3Denum face, GC3Denum fail, + GC3Denum zfail, GC3Denum zpass) +{ + LOGWEBGL("glStencilOpSeparate(%lu, %lu, %lu, %lu)", face, fail, zfail, zpass); + makeContextCurrent(); + glStencilOpSeparate(face, fail, zfail, zpass); +} + +bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, + GC3Dsizei width, GC3Dsizei height, GC3Dint border, + GC3Denum format, GC3Denum type, const void* pixels) +{ + LOGWEBGL("glTexImage2D(%u, %u, %u, %u, %u, %u, %u, %u, %p)", + target, level, internalformat, width, height, border, format, type, pixels); + if (width && height && !pixels) { + synthesizeGLError(INVALID_VALUE); + return false; + } + makeContextCurrent(); + glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); + return true; +} + +void GraphicsContext3D::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param) +{ + LOGWEBGL("glTexParameterf(%u, %u, %f)", target, pname, param); + makeContextCurrent(); + glTexParameterf(target, pname, param); +} + +void GraphicsContext3D::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param) +{ + LOGWEBGL("glTexParameteri(%u, %u, %d)", target, pname, param); + makeContextCurrent(); + glTexParameteri(target, pname, param); +} + +void GraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, + GC3Dint yoffset, GC3Dsizei width, GC3Dsizei height, + GC3Denum format, GC3Denum type, const void* pixels) +{ + LOGWEBGL("glTexSubImage2D(%u, %u, %u, %u, %u, %u, %u, %u, %p)", target, level, xoffset, + yoffset, width, height, format, type, pixels); + if (width && height && !pixels) { + synthesizeGLError(INVALID_VALUE); + return; + } + makeContextCurrent(); + glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); +} + +void GraphicsContext3D::uniform1f(GC3Dint location, GC3Dfloat x) +{ + LOGWEBGL("glUniform1f(%ld, %f)", location, x); + makeContextCurrent(); + glUniform1f(location, x); +} + +void GraphicsContext3D::uniform1fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform1fv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform1fv(location, size, v); +} + +void GraphicsContext3D::uniform1i(GC3Dint location, GC3Dint x) +{ + LOGWEBGL("glUniform1i(%ld, %d)", location, x); + makeContextCurrent(); + glUniform1i(location, x); +} + +void GraphicsContext3D::uniform1iv(GC3Dint location, GC3Dint* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform1iv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform1iv(location, size, v); +} + +void GraphicsContext3D::uniform2f(GC3Dint location, GC3Dfloat x, float y) +{ + LOGWEBGL("glUniform2f(%ld, %f, %f)", location, x, y); + makeContextCurrent(); + glUniform2f(location, x, y); +} + +void GraphicsContext3D::uniform2fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform2fv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform2fv(location, size, v); +} + +void GraphicsContext3D::uniform2i(GC3Dint location, GC3Dint x, GC3Dint y) +{ + LOGWEBGL("glUniform2i(%ld, %d, %d)", location, x, y); + makeContextCurrent(); + glUniform2i(location, x, y); +} + +void GraphicsContext3D::uniform2iv(GC3Dint location, GC3Dint* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform2iv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform2iv(location, size, v); +} + +void GraphicsContext3D::uniform3f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z) +{ + LOGWEBGL("glUniform3f(%ld, %f, %f, %f)", location, x, y, z); + makeContextCurrent(); + glUniform3f(location, x, y, z); +} + +void GraphicsContext3D::uniform3fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform3fv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform3fv(location, size, v); +} + +void GraphicsContext3D::uniform3i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z) +{ + LOGWEBGL("glUniform3i(%ld, %d, %d, %d)", location, x, y, z); + makeContextCurrent(); + glUniform3i(location, x, y, z); +} + +void GraphicsContext3D::uniform3iv(GC3Dint location, GC3Dint* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform3iv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform3iv(location, size, v); +} + +void GraphicsContext3D::uniform4f(GC3Dint location, GC3Dfloat x, GC3Dfloat y, + GC3Dfloat z, GC3Dfloat w) +{ + LOGWEBGL("glUniform4f(%ld, %f, %f, %f, %f)", location, x, y, z, w); + makeContextCurrent(); + glUniform4f(location, x, y, z, w); +} + +void GraphicsContext3D::uniform4fv(GC3Dint location, GC3Dfloat* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform4fv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform4fv(location, size, v); +} + +void GraphicsContext3D::uniform4i(GC3Dint location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w) +{ + LOGWEBGL("glUniform4i(%ld, %d, %d, %d, %d)", location, x, y, z, w); + makeContextCurrent(); + glUniform4i(location, x, y, z, w); +} + +void GraphicsContext3D::uniform4iv(GC3Dint location, GC3Dint* v, GC3Dsizei size) +{ + LOGWEBGL("glUniform4iv(%ld, %p, %d)", location, v, size); + makeContextCurrent(); + glUniform4iv(location, size, v); +} + +void GraphicsContext3D::uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, + GC3Dfloat* value, GC3Dsizei size) +{ + LOGWEBGL("glUniformMatrix2fv(%ld, %s, %p, %d)", + location, transpose ? "true" : "false", value, size); + makeContextCurrent(); + glUniformMatrix2fv(location, size, transpose, value); +} + +void GraphicsContext3D::uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, + GC3Dfloat* value, GC3Dsizei size) +{ + LOGWEBGL("glUniformMatrix3fv(%ld, %s, %p, %d)", + location, transpose ? "true" : "false", value, size); + makeContextCurrent(); + glUniformMatrix3fv(location, size, transpose, value); +} + +void GraphicsContext3D::uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, + GC3Dfloat* value, GC3Dsizei size) +{ + LOGWEBGL("glUniformMatrix4fv(%ld, %s, %p, %d)", + location, transpose ? "true" : "false", value, size); + makeContextCurrent(); + glUniformMatrix4fv(location, size, transpose, value); +} + +void GraphicsContext3D::useProgram(Platform3DObject program) +{ + LOGWEBGL("glUseProgram(%lu)", program); + makeContextCurrent(); + glUseProgram(program); +} + +void GraphicsContext3D::validateProgram(Platform3DObject program) +{ + LOGWEBGL("glValidateProgram(%lu)", program); + makeContextCurrent(); + glValidateProgram(program); +} + +void GraphicsContext3D::vertexAttrib1f(GC3Duint index, GC3Dfloat x) +{ + LOGWEBGL("glVertexAttrib1f(%lu, %f)", index, x); + makeContextCurrent(); + glVertexAttrib1f(index, x); +} + +void GraphicsContext3D::vertexAttrib1fv(GC3Duint index, GC3Dfloat* values) +{ + LOGWEBGL("glVertexAttrib1fv(%lu, %p)", index, values); + makeContextCurrent(); + glVertexAttrib1fv(index, values); +} + +void GraphicsContext3D::vertexAttrib2f(GC3Duint index, GC3Dfloat x, GC3Dfloat y) +{ + LOGWEBGL("glVertexAttrib2f(%lu, %f, %f)", index, x, y); + makeContextCurrent(); + glVertexAttrib2f(index, x, y); +} + +void GraphicsContext3D::vertexAttrib2fv(GC3Duint index, GC3Dfloat* values) +{ + LOGWEBGL("glVertexAttrib2fv(%lu, %p)", index, values); + makeContextCurrent(); + glVertexAttrib2fv(index, values); +} + +void GraphicsContext3D::vertexAttrib3f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z) +{ + LOGWEBGL("glVertexAttrib3f(%lu, %f, %f, %f)", index, x, y, z); + makeContextCurrent(); + glVertexAttrib3f(index, x, y, z); +} + +void GraphicsContext3D::vertexAttrib3fv(GC3Duint index, GC3Dfloat* values) +{ + LOGWEBGL("glVertexAttrib3fv(%lu, %p)", index, values); + makeContextCurrent(); + glVertexAttrib3fv(index, values); +} + +void GraphicsContext3D::vertexAttrib4f(GC3Duint index, GC3Dfloat x, GC3Dfloat y, + GC3Dfloat z, GC3Dfloat w) +{ + LOGWEBGL("glVertexAttrib4f(%lu, %f, %f, %f, %f)", index, x, y, z, w); + makeContextCurrent(); + glVertexAttrib4f(index, x, y, z, w); +} + +void GraphicsContext3D::vertexAttrib4fv(GC3Duint index, GC3Dfloat* values) +{ + LOGWEBGL("glVertexAttrib4fv(%lu, %p)", index, values); + makeContextCurrent(); + glVertexAttrib4fv(index, values); +} + +void GraphicsContext3D::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, + GC3Dboolean normalized, GC3Dsizei stride, + GC3Dintptr offset) +{ + LOGWEBGL("glVertexAttribPointer(%lu, %d, %d, %s, %lu, %lu)", index, size, type, + normalized ? "true" : "false", stride, offset); + makeContextCurrent(); + glVertexAttribPointer(index, size, type, normalized, stride, + reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) +{ + LOGWEBGL("viewport(%ld, %ld, %lu, %lu)", x, y, width, height); + makeContextCurrent(); + m_internal->viewport(x, y, width, height); +} + +void GraphicsContext3D::reshape(int width, int height) +{ + LOGWEBGL("reshape(%d, %d)", width, height); + if ((width == m_currentWidth) && (height == m_currentHeight)) { + return; + } + m_internal->reshape(width, height); + m_currentWidth = m_internal->width(); + m_currentHeight = m_internal->height(); +} + +void GraphicsContext3D::recreateSurface() +{ + LOGWEBGL("recreateSurface()"); + m_internal->recreateSurface(); +} + +void GraphicsContext3D::releaseSurface() +{ + LOGWEBGL("releaseSurface()"); + m_internal->releaseSurface(); +} + +IntSize GraphicsContext3D::getInternalFramebufferSize() +{ + return IntSize(m_currentWidth, m_currentHeight); +} + +void GraphicsContext3D::markContextChanged() +{ + LOGWEBGL("markContextChanged()"); + m_internal->markContextChanged(); +} + +void GraphicsContext3D::markLayerComposited() +{ + LOGWEBGL("markLayerComposited()"); + m_internal->markLayerComposited(); +} + +bool GraphicsContext3D::layerComposited() const +{ + LOGWEBGL("layerComposited()"); + return m_internal->layerComposited(); +} + +void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>) +{ +} +} +#endif diff --git a/Source/WebCore/platform/graphics/android/GraphicsContext3DInternal.cpp b/Source/WebCore/platform/graphics/android/GraphicsContext3DInternal.cpp new file mode 100644 index 0000000..85c9719 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GraphicsContext3DInternal.cpp @@ -0,0 +1,1104 @@ +/* + * Copyright (C) 2011, 2012, Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Sony Ericsson Mobile Communications AB nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL SONY ERICSSON MOBILE COMMUNICATIONS AB BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include "GraphicsContext3DInternal.h" + +#include "CurrentTime.h" +#include "Frame.h" +#include "HostWindow.h" +#include "HTMLCanvasElement.h" +#include "ImageBuffer.h" +#include "ImageData.h" +#include "PlatformGraphicsContext.h" +#include "RenderLayer.h" +#include "RenderLayerBacking.h" +#include "RenderObject.h" +#include "TilesManager.h" +#include "TransformationMatrix.h" +#include "WebViewCore.h" + +#include "SkBitmap.h" +#include "SkDevice.h" +#include <binder/IBinder.h> +#include <hardware/hardware.h> +#include <private/gui/ComposerService.h> +#include <gui/IGraphicBufferAlloc.h> +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> +#include <JNIUtility.h> + +#if ENABLE(WEBGL) +namespace WebCore { + +class WebGLFPSTimer { +public: + WebGLFPSTimer() + : m_ticks(0) + { + m_startTime = currentTime(); + } + + void tick() + { + if (++m_ticks == s_sampleRate) + reset(); + } + + void reset() + { + double totalTime = currentTime() - m_startTime; + if (totalTime > 0) { + double averageFPS = m_ticks / totalTime; + LOGWEBGL("Average FPS: %0.3f", averageFPS); + } + + m_ticks = 0; + m_startTime = currentTime(); + } + +private: + long m_ticks; + double m_startTime; + + static const int s_sampleRate; +}; + +const int WebGLFPSTimer::s_sampleRate = 15; + +#define OLD_GRAPHICBUFFER_ALLOC +class FBO { +public: + static FBO* createFBO(EGLDisplay dpy, int width, int height, GraphicsContext3D::Attributes attrs); + ~FBO(); + + EGLSyncKHR sync() { return m_sync; } + void setSync(EGLSyncKHR sync) { m_sync = sync; } + + GLuint fbo() { return m_fbo; } + EGLImageKHR image() { return m_image; } + + bool isLocked() { return m_locked; } + void setLocked(bool locked) { m_locked = locked; } + + bool lockGraphicBuffer(void** ptr) { + return (m_grBuffer.get() && + (m_grBuffer->lock(GraphicBuffer::USAGE_SW_READ_RARELY, ptr) == NO_ERROR)); + } + void unlockGraphicBuffer() { + if (m_grBuffer.get()) + m_grBuffer->unlock(); + } + + int bytesPerRow() { return m_grBuffer.get() ? m_grBuffer->getStride() * 4 : 0; } + +private: + FBO(EGLDisplay dpy); + bool init(int width, int height, GraphicsContext3D::Attributes attrs); + + GLuint createTexture(EGLImageKHR image, int width, int height); + + EGLDisplay m_dpy; + GLuint m_texture; + GLuint m_fbo; + GLuint m_depthBuffer; + GLuint m_stencilBuffer; + EGLImageKHR m_image; + EGLSyncKHR m_sync; + sp<IGraphicBufferAlloc> m_graphicBufferAlloc; + sp<GraphicBuffer> m_grBuffer; + bool m_locked; +}; + + +#define CANVAS_MAX_WIDTH 1280 +#define CANVAS_MAX_HEIGHT 1280 + +bool GraphicsContext3DInternal::s_loggingEnabled = false; + +EGLint GraphicsContext3DInternal::checkEGLError(const char* s) +{ + EGLint error = eglGetError(); + if (error == EGL_SUCCESS) { + LOGWEBGL("%s() OK", s); + } + else { + LOGWEBGL("after %s() eglError = 0x%x", s, error); + } + + return error; +} + +GLint GraphicsContext3DInternal::checkGLError(const char* s) +{ + GLint error = glGetError(); + if (error == GL_NO_ERROR) { + LOGWEBGL("%s() OK", s); + } + else { + LOGWEBGL("after %s() glError (0x%x)", s, error); + } + + return error; +} + +GraphicsContext3DInternal::GraphicsContext3DInternal(HTMLCanvasElement* canvas, + GraphicsContext3D::Attributes attrs, + HostWindow* hostWindow) + : m_proxy(new GraphicsContext3DProxy()) + , m_compositingLayer(new WebGLLayer(m_proxy.get())) + , m_canvas(canvas) + , m_attrs(attrs) + , m_layerComposited(false) + , m_canvasDirty(false) + , m_width(1) + , m_height(1) + , m_maxwidth(CANVAS_MAX_WIDTH) + , m_maxheight(CANVAS_MAX_HEIGHT) + , m_dpy(EGL_NO_DISPLAY) + , m_config(0) + , m_surface(EGL_NO_SURFACE) + , m_context(EGL_NO_CONTEXT) + , m_syncThread(0) + , m_threadState(THREAD_STATE_STOPPED) + , m_syncTimer(this, &GraphicsContext3DInternal::syncTimerFired) + , m_syncRequested(false) + , m_webGLFPSTimer(0) + , m_extensions(0) + , m_contextId(0) +{ + enableLogging(); + + //Need to initialize to a NULL state so that if you FBO creation fails later on, its in a valid state during destruction + for (int i = 0; i < NUM_BUFFERS; i++) { + m_fbo[i] = NULL; + } + + LOGWEBGL("GraphicsContext3DInternal() = %p, m_compositingLayer = %p", this, m_compositingLayer); + m_compositingLayer->ref(); + m_proxy->setGraphicsContext(this); + + if (!m_canvas || !m_canvas->document() || !m_canvas->document()->view()) + return; + JNIEnv* env = JSC::Bindings::getJNIEnv(); + WebViewCore* core = WebViewCore::getWebViewCore(m_canvas->document()->view()); + if (!core) + return; + jobject tmp = core->getWebViewJavaObject(); + m_webView = env->NewGlobalRef(tmp); + if (!m_webView) + return; + jclass webViewClass = env->GetObjectClass(m_webView); + m_postInvalidate = env->GetMethodID(webViewClass, "postInvalidate", "()V"); + env->DeleteLocalRef(webViewClass); + if (!m_postInvalidate) + return; + + if (!initEGL()) + return; + + if (!createContext(true)) { + LOGWEBGL("Create context failed. Perform JS garbage collection and try again."); + // Probably too many contexts. Force a JS garbage collection, and then try again. + // This typically only happens in Khronos Conformance tests. + m_canvas->document()->frame()->script()->lowMemoryNotification(); + if (!createContext(true)) { + LOGWEBGL("Create context still failed: aborting."); + return; + } + } + + m_webGLFPSTimer.set(new WebGLFPSTimer()); + + const char *ext = (const char *)glGetString(GL_EXTENSIONS); + LOGWEBGL("GL_EXTENSIONS = %s", ext); + // Want to keep control of which extensions are used + String extensions = ""; + if (strstr(ext, "GL_OES_texture_npot")) + extensions.append("GL_OES_texture_npot"); + if (strstr(ext, "GL_OES_packed_depth_stencil")) + extensions.append(" GL_OES_packed_depth_stencil"); + if (strstr(ext, "GL_OES_texture_float")) + extensions.append(" GL_OES_texture_float"); + m_extensions.set(new Extensions3DAndroid(extensions)); + + // ANGLE initialization. + ShBuiltInResources resources; + ShInitBuiltInResources(&resources); + + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &resources.MaxVertexAttribs); + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &resources.MaxVertexUniformVectors); + glGetIntegerv(GL_MAX_VARYING_VECTORS, &resources.MaxVaryingVectors); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &resources.MaxVertexTextureImageUnits); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &resources.MaxCombinedTextureImageUnits); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &resources.MaxTextureImageUnits); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &resources.MaxFragmentUniformVectors); + + resources.MaxDrawBuffers = 1; + m_compiler.setResources(resources); + + m_savedViewport.x = 0; + m_savedViewport.y = 0; + m_savedViewport.width = m_width; + m_savedViewport.height = m_height; + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + startSyncThread(); + + static int contextCounter = 1; + m_contextId = contextCounter++; +} + +GraphicsContext3DInternal::~GraphicsContext3DInternal() +{ + LOGWEBGL("~GraphicsContext3DInternal(), this = %p", this); + + stopSyncThread(); + + m_proxy->setGraphicsContext(0); + MutexLocker lock(m_fboMutex); + m_compositingLayer->unref(); + m_compositingLayer = 0; + deleteContext(true); + + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->DeleteGlobalRef(m_webView); +} + +bool GraphicsContext3DInternal::initEGL() +{ + m_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (m_dpy == EGL_NO_DISPLAY) + return false; + + EGLint majorVersion; + EGLint minorVersion; + EGLBoolean returnValue = eglInitialize(m_dpy, &majorVersion, &minorVersion); + if (returnValue != EGL_TRUE) + return false; + + LOGWEBGL("EGL version %d.%d", majorVersion, minorVersion); + const char *s = eglQueryString(m_dpy, EGL_VENDOR); + LOGWEBGL("EGL_VENDOR = %s", s); + s = eglQueryString(m_dpy, EGL_VERSION); + LOGWEBGL("EGL_VERSION = %s", s); + s = eglQueryString(m_dpy, EGL_EXTENSIONS); + LOGWEBGL("EGL_EXTENSIONS = %s", s); + s = eglQueryString(m_dpy, EGL_CLIENT_APIS); + LOGWEBGL("EGL_CLIENT_APIS = %s", s); + + EGLint config_attribs[21]; + int p = 0; + config_attribs[p++] = EGL_BLUE_SIZE; + config_attribs[p++] = 8; + config_attribs[p++] = EGL_GREEN_SIZE; + config_attribs[p++] = 8; + config_attribs[p++] = EGL_RED_SIZE; + config_attribs[p++] = 8; + config_attribs[p++] = EGL_SURFACE_TYPE; + config_attribs[p++] = EGL_PBUFFER_BIT; + config_attribs[p++] = EGL_RENDERABLE_TYPE; + config_attribs[p++] = EGL_OPENGL_ES2_BIT; + config_attribs[p++] = EGL_ALPHA_SIZE; + config_attribs[p++] = m_attrs.alpha ? 8 : 0; + if (m_attrs.depth) { + config_attribs[p++] = EGL_DEPTH_SIZE; + config_attribs[p++] = 16; + } + if (m_attrs.stencil) { + config_attribs[p++] = EGL_STENCIL_SIZE; + config_attribs[p++] = 8; + } + // Antialiasing currently is not supported. + m_attrs.antialias = false; + config_attribs[p] = EGL_NONE; + + EGLint num_configs = 0; + return (eglChooseConfig(m_dpy, config_attribs, &m_config, 1, &num_configs) == EGL_TRUE); +} + +bool GraphicsContext3DInternal::createContext(bool createEGLContext) +{ + LOGWEBGL("createContext()"); + EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE}; + + if (createEGLContext) { + EGLint surface_attribs[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_NONE}; + m_surface = eglCreatePbufferSurface(m_dpy, m_config, surface_attribs); + m_context = eglCreateContext(m_dpy, m_config, EGL_NO_CONTEXT, context_attribs); + } + if (m_context == EGL_NO_CONTEXT) { + deleteContext(createEGLContext); + return false; + } + + makeContextCurrent(); + for (int i = 0; i < NUM_BUFFERS; i++) { + FBO* tmp = FBO::createFBO(m_dpy, m_width > 0 ? m_width : 1, m_height > 0 ? m_height : 1, m_attrs); + if (tmp == 0) { + LOGWEBGL("Failed to create FBO"); + deleteContext(createEGLContext); + return false; + } + m_fbo[i] = tmp; + m_freeBuffers.append(tmp); + } + + m_currentFBO = dequeueBuffer(); + m_boundFBO = m_currentFBO->fbo(); + m_frontFBO = 0; + glBindFramebuffer(GL_FRAMEBUFFER, m_boundFBO); + + return true; +} + +void GraphicsContext3DInternal::deleteContext(bool deleteEGLContext) +{ + LOGWEBGL("deleteContext(%s)", deleteEGLContext ? "true" : "false"); + + makeContextCurrent(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + m_freeBuffers.clear(); + m_queuedBuffers.clear(); + m_preparedBuffers.clear(); + for (int i = 0; i < NUM_BUFFERS; i++) { + if (m_fbo[i]) { + delete m_fbo[i]; + m_fbo[i] = 0; + } + } + m_currentFBO = 0; + m_frontFBO = 0; + + eglMakeCurrent(m_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (deleteEGLContext) { + if (m_surface != EGL_NO_SURFACE) { + eglDestroySurface(m_dpy, m_surface); + m_surface = EGL_NO_SURFACE; + } + if (m_context != EGL_NO_CONTEXT) { + eglDestroyContext(m_dpy, m_context); + m_context = EGL_NO_CONTEXT; + } + } +} + +void GraphicsContext3DInternal::makeContextCurrent() +{ + if (eglGetCurrentContext() != m_context && m_context != EGL_NO_CONTEXT) { + eglMakeCurrent(m_dpy, m_surface, m_surface, m_context); + } +} + +GraphicsContext3D::Attributes GraphicsContext3DInternal::getContextAttributes() +{ + return m_attrs; +} + +unsigned long GraphicsContext3DInternal::getError() +{ + if (m_syntheticErrors.size() > 0) { + ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin(); + unsigned long err = *iter; + m_syntheticErrors.remove(iter); + return err; + } + LOGWEBGL("glGetError()"); + makeContextCurrent(); + return glGetError(); +} + +void GraphicsContext3DInternal::synthesizeGLError(unsigned long error) +{ + m_syntheticErrors.add(error); +} + +FBO* FBO::createFBO(EGLDisplay dpy, int width, int height, GraphicsContext3D::Attributes attributes) +{ + LOGWEBGL("createFBO()"); + FBO* fbo = new FBO(dpy); + + if (!fbo->init(width, height, attributes)) { + delete fbo; + return 0; + } + return fbo; +} + +FBO::FBO(EGLDisplay dpy) + : m_dpy(dpy) + , m_texture(0) + , m_fbo(0) + , m_depthBuffer(0) + , m_image(0) + , m_sync(0) + , m_grBuffer(0) + , m_locked(false) +{ +} + +bool FBO::init(int width, int height, GraphicsContext3D::Attributes attributes) +{ + // 1. Allocate a graphic buffer + sp<ISurfaceComposer> composer(ComposerService::getComposerService()); + m_graphicBufferAlloc = composer->createGraphicBufferAlloc(); + + status_t error; + + PixelFormat format = attributes.alpha ? HAL_PIXEL_FORMAT_RGBA_8888 : HAL_PIXEL_FORMAT_RGBX_8888; + + m_grBuffer = m_graphicBufferAlloc->createGraphicBuffer(width, height, format, + GRALLOC_USAGE_HW_TEXTURE, &error); + if (error != NO_ERROR) { + LOGWEBGL(" failed to allocate GraphicBuffer, error = %d", error); + return false; + } + + void *addr = 0; + if (m_grBuffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, &addr) != NO_ERROR) { + LOGWEBGL(" failed to lock the GraphicBuffer"); + return false; + } + // WebGL requires all buffers to be initialized to 0. + memset(addr, 0, width * height * 4); + m_grBuffer->unlock(); + + ANativeWindowBuffer* clientBuf = m_grBuffer->getNativeBuffer(); + if (clientBuf->handle == 0) { + LOGWEBGL(" empty handle in GraphicBuffer"); + return false; + } + + // 2. Create an EGLImage from the graphic buffer + const EGLint attrs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE, EGL_NONE + }; + + m_image = eglCreateImageKHR(m_dpy, + EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, + (EGLClientBuffer)clientBuf, + attrs); + if (GraphicsContext3DInternal::checkEGLError("eglCreateImageKHR") != EGL_SUCCESS) { + LOGWEBGL("eglCreateImageKHR() failed"); + return false; + } + + // 3. Create a texture from the EGLImage + m_texture = createTexture(m_image, width, height); + if (m_texture == 0) { + LOGWEBGL("createTexture() failed"); + return false; + } + + // 4. Create the Framebuffer Object from the texture + glGenFramebuffers(1, &m_fbo); + + if (attributes.depth) { + glGenRenderbuffers(1, &m_depthBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); + if (GraphicsContext3DInternal::checkGLError("glRenderbufferStorage") != GL_NO_ERROR) + return false; + } + + if (attributes.stencil) { + glGenRenderbuffers(1, &m_stencilBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height); + if (GraphicsContext3DInternal::checkGLError("glRenderbufferStorage") != GL_NO_ERROR) + return false; + } + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); + if (GraphicsContext3DInternal::checkGLError("glFramebufferTexture2D") != GL_NO_ERROR) + return false; + + if (attributes.depth) { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer); + if (GraphicsContext3DInternal::checkGLError("glFramebufferRenderbuffer") != GL_NO_ERROR) + return false; + } + + if (attributes.stencil) { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer); + if (GraphicsContext3DInternal::checkGLError("glFramebufferRenderbuffer") != GL_NO_ERROR) + return false; + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LOGWEBGL("Framebuffer incomplete: %d", status); + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return true; +} + +FBO::~FBO() +{ + LOGWEBGL("FBO::~FBO()"); + if (m_image) { + eglDestroyImageKHR(m_dpy, m_image); + GraphicsContext3DInternal::checkEGLError("eglDestroyImageKHR"); + } + if (m_texture) + glDeleteTextures(1, &m_texture); + if (m_depthBuffer) + glDeleteRenderbuffers(1, &m_depthBuffer); + if (m_stencilBuffer) + glDeleteRenderbuffers(1, &m_stencilBuffer); + if (m_fbo) + glDeleteFramebuffers(1, &m_fbo); +} + +GLuint FBO::createTexture(EGLImageKHR image, int width, int height) +{ + LOGWEBGL("createTexture(image = %p)", image); + GLuint texture; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + bool error = false; + if (image) { + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + error = (GraphicsContext3DInternal::checkGLError("glEGLImageTargetTexture2DOES") + != GL_NO_ERROR); + } + else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + error = (GraphicsContext3DInternal::checkGLError("glTexImage2D()") != GL_NO_ERROR); + } + glBindTexture(GL_TEXTURE_2D, 0); + if (error) { + glDeleteTextures(1, &texture); + texture = 0; + } + + return texture; +} + +void GraphicsContext3DInternal::startSyncThread() +{ + LOGWEBGL("+startSyncThread()"); + MutexLocker lock(m_threadMutex); + m_threadState = THREAD_STATE_STOPPED; + m_syncThread = createThread(syncThreadStart, this, "GraphicsContext3DInternal"); + // Wait for thread to start + while (m_threadState != THREAD_STATE_RUN) { + m_threadCondition.wait(m_threadMutex); + } + LOGWEBGL("-startSyncThread()"); +} + +void GraphicsContext3DInternal::stopSyncThread() +{ + LOGWEBGL("+stopSyncThread()"); + MutexLocker lock(m_threadMutex); + if (m_syncThread) { + m_threadState = THREAD_STATE_STOP; + // Signal thread to wake up + m_threadCondition.broadcast(); + // Wait for thread to stop + while (m_threadState != THREAD_STATE_STOPPED) { + m_threadCondition.wait(m_threadMutex); + } + m_syncThread = 0; + } + LOGWEBGL("-stopSyncThread()"); +} + +void* GraphicsContext3DInternal::syncThreadStart(void* ctx) +{ + GraphicsContext3DInternal* context = static_cast<GraphicsContext3DInternal*>(ctx); + context->runSyncThread(); + + return 0; +} + +void GraphicsContext3DInternal::runSyncThread() +{ + LOGWEBGL("SyncThread: starting"); + FBO* fbo = 0; + + MutexLocker lock(m_threadMutex); + m_threadState = THREAD_STATE_RUN; + // Signal to creator that we are up and running + m_threadCondition.broadcast(); + + while (m_threadState == THREAD_STATE_RUN) { + while (m_threadState == THREAD_STATE_RUN) { + { + MutexLocker lock(m_fboMutex); + if (!m_queuedBuffers.isEmpty()) { + fbo = m_queuedBuffers.takeFirst(); + break; + } + } + m_threadCondition.wait(m_threadMutex); + } + LOGWEBGL("SyncThread: woke after waiting for FBO, fbo = %p", fbo); + if (m_threadState != THREAD_STATE_RUN) + break; + + if (fbo->sync() != EGL_NO_SYNC_KHR) { + eglClientWaitSyncKHR(m_dpy, fbo->sync(), 0, 0); + eglDestroySyncKHR(m_dpy, fbo->sync()); + fbo->setSync(EGL_NO_SYNC_KHR); + LOGWEBGL("SyncThread: returned after waiting for Sync"); + } + + { + MutexLocker lock(m_fboMutex); + m_preparedBuffers.append(fbo); + LOGWEBGL("SyncThread: prepared buffer = %p", fbo); + updateFrontBuffer(); + } + + // Invalidate the canvas region + if (m_postInvalidate) { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_webView, m_postInvalidate); + } + } + + // Signal to calling thread that we have stopped + m_threadState = THREAD_STATE_STOPPED; + m_threadCondition.broadcast(); + LOGWEBGL("SyncThread: terminating"); +} + +PlatformLayer* GraphicsContext3DInternal::platformLayer() const +{ + LOGWEBGL("platformLayer()"); + return m_compositingLayer; +} + +void GraphicsContext3DInternal::reshape(int width, int height) +{ + LOGWEBGL("reshape(%d, %d)", width, height); + bool mustRestoreFBO = (m_boundFBO != (m_currentFBO ? m_currentFBO->fbo() : 0)); + + m_width = width > m_maxwidth ? m_maxwidth : width; + m_height = height > m_maxheight ? m_maxheight : height; + + stopSyncThread(); + makeContextCurrent(); + m_proxy->setGraphicsContext(0); + { + MutexLocker lock(m_fboMutex); + deleteContext(false); + + if (createContext(false)) { + if (!mustRestoreFBO) { + m_boundFBO = m_currentFBO->fbo(); + } + glBindFramebuffer(GL_FRAMEBUFFER, m_boundFBO); + } + } + m_proxy->setGraphicsContext(this); + startSyncThread(); +} + +void GraphicsContext3DInternal::recreateSurface() +{ + LOGWEBGL("recreateSurface()"); + if (m_currentFBO != 0) + // We already have a current surface + return; + reshape(m_width, m_height); + glViewport(m_savedViewport.x, m_savedViewport.y, m_savedViewport.width, m_savedViewport.height); +} + +void GraphicsContext3DInternal::releaseSurface() +{ + LOGWEBGL("releaseSurface(%d)", m_contextId); + if (m_currentFBO == 0) + // We don't have any current surface + return; + stopSyncThread(); + m_proxy->setGraphicsContext(0); + { + MutexLocker lock(m_fboMutex); + deleteContext(false); + } + makeContextCurrent(); + m_proxy->setGraphicsContext(this); +} + +void GraphicsContext3DInternal::syncTimerFired(Timer<GraphicsContext3DInternal>*) +{ + m_syncRequested = false; + + // Do not perform the composition step if it is an offscreen canvas + if (m_canvas->renderer()) + swapBuffers(); +} + +void GraphicsContext3DInternal::markContextChanged() +{ + if (!m_syncRequested) { + m_syncTimer.startOneShot(0); + m_syncRequested = true; + } + m_canvasDirty = true; + m_layerComposited = false; +} + +/* + * Must hold m_fboMutex when calling this function. + */ +FBO* GraphicsContext3DInternal::dequeueBuffer() +{ + LOGWEBGL("GraphicsContext3DInternal::dequeueBuffer()"); + while (m_freeBuffers.isEmpty()) { + m_fboCondition.wait(m_fboMutex); + } + FBO* fbo = m_freeBuffers.takeFirst(); + + if (fbo->sync() != EGL_NO_SYNC_KHR) { + eglClientWaitSyncKHR(m_dpy, fbo->sync(), 0, 0); + eglDestroySyncKHR(m_dpy, fbo->sync()); + fbo->setSync(EGL_NO_SYNC_KHR); + } + + return fbo; +} + +void GraphicsContext3DInternal::swapBuffers() +{ + if (s_loggingEnabled) + m_webGLFPSTimer->tick(); + + LOGWEBGL("+swapBuffers()"); + + MutexLocker lock(m_fboMutex); + FBO* fbo = m_currentFBO; + if (fbo == 0) + return; + + makeContextCurrent(); + + bool mustRestoreFBO = (m_boundFBO != fbo->fbo()); + if (mustRestoreFBO) { + glBindFramebuffer(GL_FRAMEBUFFER, fbo->fbo()); + } + + // Create the fence sync and notify the sync thread + fbo->setSync(eglCreateSyncKHR(m_dpy, EGL_SYNC_FENCE_KHR, 0)); + glFlush(); + m_queuedBuffers.append(fbo); + m_threadCondition.broadcast(); + + // Dequeue a new buffer + fbo = dequeueBuffer(); + m_currentFBO = fbo; + + if (!mustRestoreFBO) { + m_boundFBO = m_currentFBO->fbo(); + } + glBindFramebuffer(GL_FRAMEBUFFER, m_boundFBO); + m_canvasDirty = false; + m_layerComposited = true; + LOGWEBGL("-swapBuffers()"); +} + +void GraphicsContext3DInternal::updateFrontBuffer() +{ + if (!m_preparedBuffers.isEmpty()) { + if (m_frontFBO == 0) { + m_frontFBO = m_preparedBuffers.takeFirst(); + } + else if (!m_frontFBO->isLocked()) { + m_freeBuffers.append(m_frontFBO); + m_frontFBO = m_preparedBuffers.takeFirst(); + m_fboCondition.broadcast(); + } + } +} + +bool GraphicsContext3DInternal::lockFrontBuffer(EGLImageKHR& image, SkRect& rect) +{ + LOGWEBGL("GraphicsContext3DInternal::lockFrontBuffer()"); + MutexLocker lock(m_fboMutex); + FBO* fbo = m_frontFBO; + + if (!fbo || !fbo->image()) { + LOGWEBGL("-GraphicsContext3DInternal::lockFrontBuffer(), fbo = %p", fbo); + return false; + } + + fbo->setLocked(true); + image = fbo->image(); + + RenderObject* renderer = m_canvas->renderer(); + if (renderer && renderer->isBox()) { + RenderBox* box = (RenderBox*)renderer; + rect.setXYWH(box->borderLeft() + box->paddingLeft(), + box->borderTop() + box->paddingTop(), + box->contentWidth(), + box->contentHeight()); + } + + return true; +} + +void GraphicsContext3DInternal::releaseFrontBuffer() +{ + LOGWEBGL("GraphicsContext3DInternal::releaseFrontBuffer()"); + MutexLocker lock(m_fboMutex); + FBO* fbo = m_frontFBO; + + if (fbo) { + fbo->setLocked(false); + if (fbo->sync() != EGL_NO_SYNC_KHR) { + eglDestroySyncKHR(m_dpy, fbo->sync()); + } + fbo->setSync(eglCreateSyncKHR(m_dpy, EGL_SYNC_FENCE_KHR, 0)); + } + updateFrontBuffer(); +} + +void GraphicsContext3DInternal::paintRenderingResultsToCanvas(CanvasRenderingContext* context) +{ + LOGWEBGL("paintRenderingResultsToCanvas()"); + ImageBuffer* imageBuffer = context->canvas()->buffer(); + const SkBitmap& canvasBitmap = + imageBuffer->context()->platformContext()->recordingCanvas()->getDevice()->accessBitmap(false); + SkCanvas canvas(canvasBitmap); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, m_width, m_height); + bitmap.allocPixels(); + unsigned char *pixels = static_cast<unsigned char*>(bitmap.getPixels()); + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + SkRect dstRect; + dstRect.iset(0, 0, imageBuffer->size().width(), imageBuffer->size().height()); + canvas.drawBitmapRect(bitmap, 0, dstRect); +} + +PassRefPtr<ImageData> GraphicsContext3DInternal::paintRenderingResultsToImageData() +{ + LOGWEBGL("paintRenderingResultsToImageData()"); + + // Reading premultiplied alpha would involve unpremultiplying, which is lossy. + if (m_attrs.premultipliedAlpha) + return 0; + + RefPtr<ImageData> imageData = ImageData::create(IntSize(m_width, m_height)); + unsigned char* pixels = imageData->data()->data()->data(); + + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + return imageData; +} + +bool GraphicsContext3DInternal::paintCompositedResultsToCanvas(CanvasRenderingContext* context) +{ + LOGWEBGL("paintCompositedResultsToCanvas()"); + ImageBuffer* imageBuffer = context->canvas()->buffer(); + const SkBitmap& canvasBitmap = + imageBuffer->context()->platformContext()->recordingCanvas()->getDevice()->accessBitmap(false); + SkCanvas canvas(canvasBitmap); + + MutexLocker lock(m_fboMutex); + + FBO* fbo = m_frontFBO; + if (!fbo) + return false; + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, m_width, m_height, fbo->bytesPerRow()); + + unsigned char* bits = NULL; + if (fbo->lockGraphicBuffer((void**)&bits)) { + bitmap.setPixels(bits); + + SkRect dstRect; + dstRect.iset(0, 0, imageBuffer->size().width(), imageBuffer->size().height()); + canvas.save(); + canvas.translate(0, SkIntToScalar(imageBuffer->size().height())); + canvas.scale(SK_Scalar1, -SK_Scalar1); + canvas.drawBitmapRect(bitmap, 0, dstRect); + canvas.restore(); + bitmap.setPixels(0); + fbo->unlockGraphicBuffer(); + } + + return true; +} + +void GraphicsContext3DInternal::bindFramebuffer(GC3Denum target, Platform3DObject buffer) +{ + LOGWEBGL("glBindFrameBuffer(%d, %d)", target, buffer); + makeContextCurrent(); + MutexLocker lock(m_fboMutex); + if (!buffer && m_currentFBO) { + buffer = m_currentFBO->fbo(); + } + glBindFramebuffer(target, buffer); + m_boundFBO = buffer; +} + +void GraphicsContext3DInternal::compileShader(Platform3DObject shader) +{ + LOGWEBGL("compileShader()"); + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + if (result == m_shaderSourceMap.end()) { + LOGWEBGL(" shader not found"); + return; + } + ShaderSourceEntry& entry = result->second; + + int shaderType; + glGetShaderiv(shader, GL_SHADER_TYPE, &shaderType); + + ANGLEShaderType ast = shaderType == GL_VERTEX_SHADER ? + SHADER_TYPE_VERTEX : SHADER_TYPE_FRAGMENT; + + String src; + String log; + bool isValid = m_compiler.validateShaderSource(entry.source.utf8().data(), ast, src, log); + + entry.log = log; + entry.isValid = isValid; + + if (!isValid) { + LOGWEBGL(" shader validation failed"); + return; + } + int len = entry.source.length(); + CString cstr = entry.source.utf8(); + const char* s = cstr.data(); + + LOGWEBGL("glShaderSource(%s)", cstr.data()); + glShaderSource(shader, 1, &s, &len); + + LOGWEBGL("glCompileShader()"); + glCompileShader(shader); +} + +String GraphicsContext3DInternal::getShaderInfoLog(Platform3DObject shader) +{ + LOGWEBGL("getShaderInfoLog()"); + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + + if (result == m_shaderSourceMap.end()) { + LOGWEBGL(" shader not found"); + return ""; + } + + ShaderSourceEntry entry = result->second; + + if (entry.isValid) { + LOGWEBGL(" validated shader, retrieve OpenGL log"); + GLuint shaderID = shader; + GLint logLength; + glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLength); + if (!logLength) + return ""; + + char* log = 0; + if ((log = (char *)fastMalloc(logLength * sizeof(char))) == 0) + return ""; + GLsizei returnedLogLength; + glGetShaderInfoLog(shaderID, logLength, &returnedLogLength, log); + String res = String(log, returnedLogLength); + fastFree(log); + + return res; + } + else { + LOGWEBGL(" non-validated shader, use ANGLE log"); + return entry.log; + } +} + +String GraphicsContext3DInternal::getShaderSource(Platform3DObject shader) +{ + LOGWEBGL("getShaderSource()"); + HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); + + if (result == m_shaderSourceMap.end()) + return ""; + + return result->second.source; +} + +void GraphicsContext3DInternal::shaderSource(Platform3DObject shader, const String& string) +{ + LOGWEBGL("shaderSource()"); + ShaderSourceEntry entry; + + entry.source = string; + + m_shaderSourceMap.set(shader, entry); +} + +void GraphicsContext3DInternal::viewport(long x, long y, unsigned long width, unsigned long height) +{ + LOGWEBGL("glViewport(%d, %d, %d, %d)", x, y, width, height); + glViewport(x, y, width, height); + m_savedViewport.x = x; + m_savedViewport.y = y; + m_savedViewport.width = width; + m_savedViewport.height = height; +} + +void GraphicsContext3DInternal::enableLogging() +{ + char value[PROPERTY_VALUE_MAX]; + property_get("debug.webgl", value, "0"); + s_loggingEnabled = atoi(value) ? true : false; +} + +} +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/android/GraphicsContext3DInternal.h b/Source/WebCore/platform/graphics/android/GraphicsContext3DInternal.h new file mode 100644 index 0000000..513de49 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GraphicsContext3DInternal.h @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2011, 2012, Sony Ericsson Mobile Communications AB + * Copyright (C) 2012, Sony Mobile Communications AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Sony Ericsson Mobile Communications AB nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL SONY ERICSSON MOBILE COMMUNICATIONS AB BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsContext3DInternal_h +#define GraphicsContext3D3DInternal_h + +#include "ANGLEWebKitBridge.h" +#include "CanvasRenderingContext.h" +#include "Extensions3DAndroid.h" +#include "GraphicsContext3D.h" +#include "HTMLCanvasElement.h" +#include "SkRect.h" +#include "Threading.h" +#include "Timer.h" +#include "TransformationMatrix.h" +#include "WebGLLayer.h" + +#include <wtf/Deque.h> +#include <wtf/RefPtr.h> + +#include <EGL/egl.h> +#include <GLES2/gl2.h> +#include <ui/GraphicBuffer.h> + +// This can be increased to 3, for example, if that has a positive impact on performance. +#define NUM_BUFFERS 2 + +#include <cutils/properties.h> +#include <cutils/log.h> + +#define LOGWEBGL(...) (GraphicsContext3DInternal::s_loggingEnabled ? \ + (void)android_printLog(ANDROID_LOG_DEBUG, "WebGL", __VA_ARGS__) : (void)0) + +using namespace android; + +namespace WebCore { + +#define CLAMP(x) GraphicsContext3DInternal::clampValue(x) + +typedef enum { + THREAD_STATE_STOPPED, + THREAD_STATE_RUN, + THREAD_STATE_RESTART, + THREAD_STATE_STOP +} thread_state_t; + +class WebGLFPSTimer; +class GraphicsContext3DProxy; +class FBO; + +class GraphicsContext3DInternal : public RefCounted<GraphicsContext3DInternal> { +public: + GraphicsContext3DInternal(HTMLCanvasElement* canvas, GraphicsContext3D::Attributes attrs, + HostWindow* hostWindow); + ~GraphicsContext3DInternal(); + + bool isValid() { return m_contextId > 0; } + + PlatformLayer* platformLayer() const; + + void makeContextCurrent(); + GraphicsContext3D::Attributes getContextAttributes(); + void reshape(int width, int height); + + unsigned long getError(); + void synthesizeGLError(unsigned long error); + + void recreateSurface(); + void releaseSurface(); + + void markContextChanged(); + void markLayerComposited() { m_layerComposited = true; } + bool layerComposited() const { return m_layerComposited; } + + void updateFrontBuffer(); + bool lockFrontBuffer(EGLImageKHR& image, SkRect& rect); + void releaseFrontBuffer(); + + void paintRenderingResultsToCanvas(CanvasRenderingContext* context); + PassRefPtr<ImageData> paintRenderingResultsToImageData(); + bool paintCompositedResultsToCanvas(CanvasRenderingContext* context); + + // Shader handling, required since we validate shader source with ANGLE + void compileShader(Platform3DObject shader); + String getShaderInfoLog(Platform3DObject shader); + String getShaderSource(Platform3DObject shader); + void shaderSource(Platform3DObject shader, const String& string); + + void viewport(long x, long y, unsigned long width, unsigned long height); + + int width() { return m_width; } + int height() { return m_height; } + + Extensions3D* getExtensions() { return m_extensions.get(); } + + void bindFramebuffer(GC3Denum target, Platform3DObject buffer); + + static GLclampf clampValue(GLclampf x) { + GLclampf tmp = x; + if (tmp < 0.0f) + tmp = 0.0f; + else if (tmp > 1.0f) + tmp = 1.0f; + return tmp; + } + + static GLclampf clampValue(double d) { + GLclampf tmp = (GLclampf)d; + if (tmp < 0.0f) + tmp = 0.0f; + else if (tmp > 1.0f) + tmp = 1.0f; + return tmp; + } + + static EGLint checkEGLError(const char* s); + static GLint checkGLError(const char* s); + static void enableLogging(); + static bool s_loggingEnabled; + +private: + bool initEGL(); + bool createContext(bool createEGLContext); + void deleteContext(bool deleteEGLContext); + + RefPtr<GraphicsContext3DProxy> m_proxy; + WebGLLayer *m_compositingLayer; + HTMLCanvasElement* m_canvas; + GraphicsContext3D::Attributes m_attrs; + bool m_layerComposited; + bool m_canvasDirty; + + int m_width; + int m_height; + int m_maxwidth; + int m_maxheight; + + EGLDisplay m_dpy; + EGLConfig m_config; + EGLSurface m_surface; + EGLContext m_context; + + // Routines for FBOs + FBO* m_fbo[NUM_BUFFERS]; + GLuint m_boundFBO; + FBO* m_currentFBO; + FBO* m_frontFBO; + Deque<FBO*> m_freeBuffers; + Deque<FBO*> m_queuedBuffers; + Deque<FBO*> m_preparedBuffers; + WTF::Mutex m_fboMutex; + WTF::ThreadCondition m_fboCondition; + + void startSyncThread(); + void stopSyncThread(); + static void* syncThreadStart(void* ctx); + void runSyncThread(); + ThreadIdentifier m_syncThread; + thread_state_t m_threadState; + WTF::Mutex m_threadMutex; + WTF::ThreadCondition m_threadCondition; + + void syncTimerFired(Timer<GraphicsContext3DInternal>*); + FBO* dequeueBuffer(); + void swapBuffers(); + Timer<GraphicsContext3DInternal> m_syncTimer; + bool m_syncRequested; + + OwnPtr<WebGLFPSTimer> m_webGLFPSTimer; + + typedef struct { + String source; + String log; + bool isValid; + } ShaderSourceEntry; + HashMap<Platform3DObject, ShaderSourceEntry> m_shaderSourceMap; + ANGLEWebKitBridge m_compiler; + + // Errors raised by synthesizeGLError(). + ListHashSet<unsigned long> m_syntheticErrors; + + struct { + GLint x, y; + GLsizei width, height; + } m_savedViewport; + OwnPtr<Extensions3DAndroid> m_extensions; + int m_contextId; + + // Java method used for invalidating the canvas area + jobject m_webView; + jmethodID m_postInvalidate; +}; + +} // namespace WebCore + +#endif // GraphicsContext3DInternal_h diff --git a/Source/WebCore/platform/graphics/android/GraphicsContext3DProxy.cpp b/Source/WebCore/platform/graphics/android/GraphicsContext3DProxy.cpp new file mode 100644 index 0000000..0d273bb --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GraphicsContext3DProxy.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WEBGL) + +#include "GraphicsContext3DProxy.h" +#include "GraphicsContext3DInternal.h" + +namespace WebCore { + +GraphicsContext3DProxy::GraphicsContext3DProxy() +{ + LOGWEBGL("GraphicsContext3DProxy::GraphicsContext3DProxy(), this = %p", this); +} + +GraphicsContext3DProxy::~GraphicsContext3DProxy() +{ + LOGWEBGL("GraphicsContext3DProxy::~GraphicsContext3DProxy(), this = %p", this); +} + +void GraphicsContext3DProxy::setGraphicsContext(GraphicsContext3DInternal* context) +{ + MutexLocker lock(m_mutex); + m_context = context; +} + +void GraphicsContext3DProxy::incr() +{ + MutexLocker lock(m_mutex); + m_refcount++; +} + +void GraphicsContext3DProxy::decr() +{ + MutexLocker lock(m_mutex); + m_refcount--; + if (m_refcount == 0) { + glDeleteTextures(1, &m_texture); + m_texture = 0; + } +} + +bool GraphicsContext3DProxy::lockFrontBuffer(GLuint& texture, SkRect& rect) +{ + MutexLocker lock(m_mutex); + if (!m_context) { + return false; + } + EGLImageKHR image; + bool locked = m_context->lockFrontBuffer(image, rect); + if (locked) { + if (m_texture == 0) + glGenTextures(1, &m_texture); + + glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_texture); + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); + texture = m_texture; + } + + return locked; +} + +void GraphicsContext3DProxy::releaseFrontBuffer() +{ + MutexLocker lock(m_mutex); + if (!m_context) { + return; + } + glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); + m_context->releaseFrontBuffer(); +} +} +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/platform/graphics/android/GraphicsContext3DProxy.h b/Source/WebCore/platform/graphics/android/GraphicsContext3DProxy.h new file mode 100644 index 0000000..060acdf --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GraphicsContext3DProxy.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsContext3DProxy_h +#define GraphicsContext3DProxy_h + +#include "config.h" + +#include "SkRect.h" +#include "Threading.h" +#include <wtf/RefCounted.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> + +namespace WebCore { + +class GraphicsContext3DInternal; + +class GraphicsContext3DProxy: public RefCounted<GraphicsContext3DProxy> { +public: + GraphicsContext3DProxy(); + ~GraphicsContext3DProxy(); + + void setGraphicsContext(GraphicsContext3DInternal* context); + void incr(); + void decr(); + + bool lockFrontBuffer(GLuint& texture, SkRect& rect); + void releaseFrontBuffer(); + +private: + WTF::Mutex m_mutex; + GraphicsContext3DInternal* m_context; + GLuint m_texture; + int m_refcount; +}; + +} +#endif diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 6edbe6a..3196895 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011, Sony Ericsson Mobile Communications AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -106,6 +107,9 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_haveContents(false), m_newImage(false), m_image(0), +#if ENABLE(WEBGL) + m_is3DCanvas(false), +#endif m_fixedBackgroundLayer(0), m_foregroundLayer(0), m_foregroundClipLayer(0) @@ -478,6 +482,14 @@ void GraphicsLayerAndroid::setNeedsDisplay() setNeedsDisplayInRect(rect); } +#if ENABLE(WEBGL) +void GraphicsLayerAndroid::setContentsNeedsDisplay() +{ + if (m_is3DCanvas) + setNeedsDisplay(); +} +#endif + // Helper to set and clear the painting phase as well as auto restore the // original phase. class PaintingPhase { @@ -1074,6 +1086,28 @@ void GraphicsLayerAndroid::setContentsToMedia(PlatformLayer* mediaLayer) } } +#if ENABLE(WEBGL) +void GraphicsLayerAndroid::setContentsToCanvas(PlatformLayer* canvasLayer) +{ + if (m_contentLayer != canvasLayer && canvasLayer) { + // Copy data from the original content layer to the new one + canvasLayer->setPosition(m_contentLayer->getPosition().fX, + m_contentLayer->getPosition().fY); + canvasLayer->setSize(m_contentLayer->getWidth(), m_contentLayer->getHeight()); + canvasLayer->setDrawTransform(*m_contentLayer->drawTransform()); + + canvasLayer->ref(); + m_contentLayer->unref(); + m_contentLayer = canvasLayer; + + m_needsSyncChildren = true; + m_is3DCanvas = true; + + setDrawsContent(true); + } +} +#endif + PlatformLayer* GraphicsLayerAndroid::platformLayer() const { ALOGV("platformLayer"); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 28d4b09..5418745 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2011, Sony Ericsson Mobile Communications AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -92,6 +93,10 @@ public: virtual void setNeedsDisplay(); virtual void setNeedsDisplayInRect(const FloatRect&); +#if ENABLE(WEBGL) + virtual void setContentsNeedsDisplay(); +#endif + virtual bool addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, @@ -116,6 +121,9 @@ public: virtual void setContentsToImage(Image*); virtual void setContentsToMedia(PlatformLayer*); +#if ENABLE(WEBGL) + virtual void setContentsToCanvas(PlatformLayer*); +#endif virtual PlatformLayer* platformLayer() const; void pauseDisplay(bool state); @@ -165,6 +173,12 @@ private: bool m_newImage; Image* m_image; +#if ENABLE(WEBGL) + bool m_is3DCanvas; +#endif + + SkRegion m_dirtyRegion; + LayerAndroid* m_contentLayer; FixedBackgroundImageLayerAndroid* m_fixedBackgroundLayer; LayerAndroid* m_foregroundLayer; diff --git a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp index f36200d..9571ec2 100644 --- a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp @@ -30,6 +30,7 @@ #include "BitmapImage.h" #include "ColorSpace.h" #include "GraphicsContext.h" +#include "MIMETypeRegistry.h" #include "NotImplemented.h" #include "PlatformBridge.h" #include "PlatformGraphicsContext.h" @@ -43,6 +44,10 @@ #include "SkStream.h" #include "SkUnPreMultiply.h" +#include "image-encoders/skia/JPEGImageEncoder.h" +#include "image-encoders/skia/PNGImageEncoder.h" +#include <wtf/text/StringConcatenate.h> + using namespace std; namespace WebCore { @@ -245,8 +250,36 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou } } +template <typename T> +static String ImageToDataURL(T& source, const String& mimeType, const double* quality) +{ + ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)); + + Vector<unsigned char> encodedImage; + if (mimeType == "image/jpeg") { + int compressionQuality = JPEGImageEncoder::DefaultCompressionQuality; + if (quality && *quality >= 0.0 && *quality <= 1.0) + compressionQuality = static_cast<int>(*quality * 100 + 0.5); + if (!JPEGImageEncoder::encode(source, compressionQuality, &encodedImage)) + return "data:,"; + } else { + if (!PNGImageEncoder::encode(source, &encodedImage)) + return "data:,"; + ASSERT(mimeType == "image/png"); + } + + Vector<char> base64Data; + base64Encode(*reinterpret_cast<Vector<char>*>(&encodedImage), base64Data); + + return makeString("data:", mimeType, ";base64,", base64Data); +} + +String ImageDataToDataURL(const ImageData& source, const String& mimeType, const double* quality) +{ + return ImageToDataURL(source, mimeType, quality); +} -String ImageBuffer::toDataURL(const String&, const double*) const +String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const { // Encode the image into a vector. SkDynamicMemoryWStream pngStream; diff --git a/Source/WebCore/platform/graphics/android/WebGLLayer.cpp b/Source/WebCore/platform/graphics/android/WebGLLayer.cpp new file mode 100644 index 0000000..af1f31d --- /dev/null +++ b/Source/WebCore/platform/graphics/android/WebGLLayer.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011, 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#if ENABLE(WEBGL) && USE(ACCELERATED_COMPOSITING) + +#include "WebGLLayer.h" + +#include "GraphicsContext3DInternal.h" +#include "DrawQuadData.h" +#include "SkRect.h" +#include "TilesManager.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +WebGLLayer::WebGLLayer(GraphicsContext3DProxy* proxy) + : LayerAndroid((RenderLayer*)0) + , m_proxy(proxy) +{ + m_proxy->incr(); +} + +WebGLLayer::WebGLLayer(const WebGLLayer& layer) + : LayerAndroid(layer) + , m_proxy(layer.m_proxy) +{ + m_proxy->incr(); +} + +WebGLLayer::~WebGLLayer() +{ + m_proxy->decr(); +} + +bool WebGLLayer::drawGL(bool layerTilesDisabled) +{ + bool askScreenUpdate = false; + + askScreenUpdate |= LayerAndroid::drawGL(layerTilesDisabled); + + if (m_proxy.get()) { + GLuint texture; + SkRect localBounds; + bool locked = m_proxy->lockFrontBuffer(texture, localBounds); + if (locked) { + // Flip the y-coordinate + TransformationMatrix transform = m_drawTransform; + transform = transform.translate(0, 2 * localBounds.top() + localBounds.height()); + transform = transform.scale3d(1.0, -1.0, 1.0); + TextureQuadData data(texture, GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, LayerQuad, &transform, &localBounds); + TilesManager::instance()->shader()->drawQuad(&data); + m_proxy->releaseFrontBuffer(); + } + } + + return askScreenUpdate; +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) && USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/WebGLLayer.h b/Source/WebCore/platform/graphics/android/WebGLLayer.h new file mode 100644 index 0000000..e7371f7 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/WebGLLayer.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011, 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebGLLayer_h +#define WebGLLayer_h + +#include "config.h" + +#if ENABLE(WEBGL) && USE(ACCELERATED_COMPOSITING) + +#include "GLUtils.h" +#include "GraphicsContext3DProxy.h" +#include "LayerAndroid.h" +#include "RefPtr.h" +#include <jni.h> + +namespace WebCore { + +class GraphicsContext3DInternal; + +class WebGLLayer : public LayerAndroid { +public: + WebGLLayer(GraphicsContext3DProxy* proxy); + WebGLLayer(const WebGLLayer& layer); + virtual ~WebGLLayer(); + + virtual LayerAndroid* copy() const { return new WebGLLayer(*this); } + virtual bool drawGL(bool layerTilesDisabled); + virtual bool isWebGL() const { return true; } + +private: + RefPtr<GraphicsContext3DProxy> m_proxy; +}; + +} // namespace WebCore + +#endif // ENABLE(WEBGL) && USE(ACCELERATED_COMPOSITING) +#endif // WebGLLayer_h diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp index 1064388..d58c4ee 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp @@ -27,7 +27,7 @@ #include "SkPaint.h" #include "SkPicture.h" #include "SkTypeface.h" -#include "Surface.h" +#include "rendering/Surface.h" #include "TilesManager.h" #include <wtf/CurrentTime.h> @@ -148,8 +148,8 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), } if (hasAbsoluteChildren && !hasOnlyAbsoluteFollowers) { - Vector<LayerAndroid*> normalLayers; - Vector<LayerAndroid*> absoluteLayers; + WTF::Vector<LayerAndroid*> normalLayers; + WTF::Vector<LayerAndroid*> absoluteLayers; for (int i = 0; i < layer.countChildren(); i++) { LayerAndroid* child = layer.getChild(i); if (child->isPositionAbsolute() @@ -307,7 +307,7 @@ void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim) void LayerAndroid::removeAnimationsForProperty(AnimatedPropertyID property) { KeyframesMap::const_iterator end = m_animations.end(); - Vector<pair<String, int> > toDelete; + WTF::Vector<pair<String, int> > toDelete; for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) { if ((it->second)->type() == property) toDelete.append(it->first); @@ -320,7 +320,7 @@ void LayerAndroid::removeAnimationsForProperty(AnimatedPropertyID property) void LayerAndroid::removeAnimationsForKeyframes(const String& name) { KeyframesMap::const_iterator end = m_animations.end(); - Vector<pair<String, int> > toDelete; + WTF::Vector<pair<String, int> > toDelete; for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) { if ((it->second)->isNamed(name)) toDelete.append(it->first); @@ -704,7 +704,7 @@ void LayerAndroid::assignSurfaces(LayerMergeState* mergeState) int count = this->countChildren(); if (count > 0) { mergeState->depth++; - Vector <LayerAndroid*> sublayers; + WTF::Vector <LayerAndroid*> sublayers; for (int i = 0; i < count; i++) sublayers.append(getChild(i)); @@ -895,7 +895,7 @@ bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas, PaintStyle style) bool askScreenUpdate = false; int count = this->countChildren(); if (count > 0) { - Vector <LayerAndroid*> sublayers; + WTF::Vector <LayerAndroid*> sublayers; for (int i = 0; i < count; i++) sublayers.append(this->getChild(i)); diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h index 6c2e43d..b3518e9 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h @@ -243,6 +243,7 @@ public: virtual bool isIFrame() const { return false; } virtual bool isIFrameContent() const { return false; } virtual bool isFixedBackground() const { return false; } + virtual bool isWebGL() const { return false; } bool isPositionFixed() const { return m_fixedPosition; } void setAbsolutePosition(bool isAbsolute) { m_isPositionAbsolute = isAbsolute; } diff --git a/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h b/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h index 346afe4..e0975ee 100644 --- a/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h +++ b/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h @@ -120,7 +120,7 @@ private: // The retiredTextures is used to communicate between UI thread and webcore // thread. Basically, GL textures are determined to retire in the webcore // thread, and really get deleted in the UI thread. - Vector<GLuint> m_retiredTextures; + WTF::Vector<GLuint> m_retiredTextures; android::Mutex m_retiredTexturesLock; GLuint createTextureFromImage(RenderSkinMediaButton::MediaButton buttonType); diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.cpp b/Source/WebCore/platform/image-decoders/ImageDecoder.cpp index 24a9f90..504eb08 100644 --- a/Source/WebCore/platform/image-decoders/ImageDecoder.cpp +++ b/Source/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2008-2009 Torch Mobile, Inc. * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * Copyright (C) 2012, Sony Ericsson Mobile Communications AB * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -94,10 +95,10 @@ bool matchesCURSignature(char* contents) } -#if !OS(ANDROID) // This method requires BMPImageDecoder, PNGImageDecoder, ICOImageDecoder and // JPEGDecoder, which aren't used on Android, and which don't all compile. // TODO: Find a better fix. +// WebGL: Activated the GIF and PNG image decoders for Android. ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) { static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP" @@ -109,9 +110,12 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaO if (matchesGIFSignature(contents)) return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption); +#if !OS(ANDROID) || ENABLE(WEBGL) if (matchesPNGSignature(contents)) return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption); +#endif +#if !OS(ANDROID) if (matchesJPEGSignature(contents)) return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption); @@ -125,10 +129,10 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaO if (matchesICOSignature(contents) || matchesCURSignature(contents)) return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption); +#endif // !OS(ANDROID) return 0; } -#endif // !OS(ANDROID) #if !USE(SKIA) diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h index 53e1160..4c7abcb 100644 --- a/Source/WebCore/platform/network/ResourceRequestBase.h +++ b/Source/WebCore/platform/network/ResourceRequestBase.h @@ -65,6 +65,7 @@ namespace WebCore { TargetIsWorker, TargetIsSharedWorker, TargetIsPrefetch, + TargetIsPrerender, TargetIsFavicon, }; diff --git a/Source/WebCore/platform/network/android/ResourceRequest.h b/Source/WebCore/platform/network/android/ResourceRequest.h index 745c2ef..456f016 100644 --- a/Source/WebCore/platform/network/android/ResourceRequest.h +++ b/Source/WebCore/platform/network/android/ResourceRequest.h @@ -28,7 +28,6 @@ #ifndef ResourceRequest_h #define ResourceRequest_h -#include "CachedResource.h" #include "ResourceRequestBase.h" namespace WebCore { |