diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/texmap')
52 files changed, 5735 insertions, 1860 deletions
diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTexture.cpp b/Source/WebCore/platform/graphics/texmap/BitmapTexture.cpp new file mode 100644 index 000000000..487077be9 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTexture.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" +#include "BitmapTexture.h" + +#include "GraphicsLayer.h" +#include "ImageBuffer.h" +#include "TextureMapper.h" + +namespace WebCore { + +void BitmapTexture::updateContents(TextureMapper&, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag, float scale) +{ + // Making an unconditionally unaccelerated buffer here is OK because this code + // isn't used by any platforms that respect the accelerated bit. + std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(targetRect.size(), Unaccelerated); + + if (!imageBuffer) + return; + + GraphicsContext& context = imageBuffer->context(); + context.setImageInterpolationQuality(InterpolationDefault); + context.setTextDrawingMode(TextModeFill); + + IntRect sourceRect(targetRect); + sourceRect.setLocation(offset); + sourceRect.scale(1 / scale); + context.applyDeviceScaleFactor(scale); + context.translate(-sourceRect.x(), -sourceRect.y()); + + sourceLayer->paintGraphicsLayerContents(context, sourceRect); + + RefPtr<Image> image = imageBuffer->copyImage(DontCopyBackingStore); + if (!image) + return; + + updateContents(image.get(), targetRect, IntPoint(), updateContentsFlag); +} + +} // namespace diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTexture.h b/Source/WebCore/platform/graphics/texmap/BitmapTexture.h new file mode 100644 index 000000000..3245638a8 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTexture.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 BitmapTexture_h +#define BitmapTexture_h + +#include "IntPoint.h" +#include "IntRect.h" +#include "IntSize.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class FilterOperations; +class GraphicsLayer; +class Image; +class TextureMapper; + +// A 2D texture that can be the target of software or GL rendering. +class BitmapTexture : public RefCounted<BitmapTexture> { +public: + enum Flag { + NoFlag = 0, + SupportsAlpha = 0x01, + FBOAttachment = 0x02 + }; + + enum UpdateContentsFlag { + UpdateCanModifyOriginalImageData, + UpdateCannotModifyOriginalImageData + }; + + typedef unsigned Flags; + + BitmapTexture() + : m_flags(0) + { + } + + virtual ~BitmapTexture() { } + virtual bool isBackedByOpenGL() const { return false; } + + virtual IntSize size() const = 0; + virtual void updateContents(Image*, const IntRect&, const IntPoint& offset, UpdateContentsFlag) = 0; + virtual void updateContents(TextureMapper&, GraphicsLayer*, const IntRect& target, const IntPoint& offset, UpdateContentsFlag, float scale = 1); + virtual void updateContents(const void*, const IntRect& target, const IntPoint& offset, int bytesPerLine, UpdateContentsFlag) = 0; + virtual bool isValid() const = 0; + inline Flags flags() const { return m_flags; } + + virtual int bpp() const { return 32; } + void reset(const IntSize& size, Flags flags = 0) + { + m_flags = flags; + m_contentSize = size; + didReset(); + } + virtual void didReset() { } + + inline IntSize contentSize() const { return m_contentSize; } + inline int numberOfBytes() const { return size().width() * size().height() * bpp() >> 3; } + inline bool isOpaque() const { return !(m_flags & SupportsAlpha); } + + virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper&, const FilterOperations&) { return this; } + +protected: + IntSize m_contentSize; + +private: + Flags m_flags; +}; + +} + +#endif // BitmapTexture_h diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp b/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp new file mode 100644 index 000000000..589060224 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.cpp @@ -0,0 +1,347 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Igalia S.L. + Copyright (C) 2012 Adobe Systems Incorporated + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "BitmapTextureGL.h" + +#if USE(TEXTURE_MAPPER_GL) + +#include "Extensions3D.h" +#include "FilterOperations.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "LengthFunctions.h" +#include "NotImplemented.h" +#include "TextureMapperShaderProgram.h" +#include "Timer.h" +#include <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#if USE(CAIRO) +#include "CairoUtilities.h" +#include "RefPtrCairo.h" +#include <cairo.h> +#include <wtf/text/CString.h> +#endif + +#if OS(DARWIN) +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#endif + +namespace WebCore { + +BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture) +{ + if (!texture || !texture->isBackedByOpenGL()) + return 0; + + return static_cast<BitmapTextureGL*>(texture); +} + +BitmapTextureGL::BitmapTextureGL(RefPtr<GraphicsContext3D>&& context3D, const Flags flags) + : m_context3D(WTFMove(context3D)) +{ + if (flags & FBOAttachment) + m_internalFormat = m_format = GraphicsContext3D::RGBA; + else { + // If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES + // internal and external formats need to be BGRA + m_internalFormat = GraphicsContext3D::RGBA; + m_format = GraphicsContext3D::BGRA; + if (m_context3D->isGLES2Compliant()) { + if (m_context3D->getExtensions().supports("GL_EXT_texture_format_BGRA8888")) + m_internalFormat = GraphicsContext3D::BGRA; + else + m_format = GraphicsContext3D::RGBA; + } + } +} + +static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = 0) +{ + stride = stride ? stride : rect.width(); + for (int y = rect.y(); y < rect.maxY(); ++y) { + uint32_t* p = data + y * stride; + for (int x = rect.x(); x < rect.maxX(); ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } +} + +static bool driverSupportsSubImage(GraphicsContext3D* context) +{ + if (context->isGLES2Compliant()) { + static bool supportsSubImage = context->getExtensions().supports("GL_EXT_unpack_subimage"); + return supportsSubImage; + } + + return true; +} + +void BitmapTextureGL::didReset() +{ + if (!m_id) + m_id = m_context3D->createTexture(); + + m_shouldClear = true; + if (m_textureSize == contentSize()) + return; + + m_textureSize = contentSize(); + m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); + m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); + + m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, m_internalFormat, m_textureSize.width(), m_textureSize.height(), 0, m_format, m_type, 0); +} + +void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat) +{ + m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); + // For ES drivers that don't support sub-images. + if (driverSupportsSubImage(m_context3D.get())) { + // Use the OpenGL sub-image extension, now that we know it's available. + m_context3D->pixelStorei(GraphicsContext3D::UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel); + m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_ROWS, sourceOffset.y()); + m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_PIXELS, sourceOffset.x()); + } + + m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, m_type, srcData); + + // For ES drivers that don't support sub-images. + if (driverSupportsSubImage(m_context3D.get())) { + m_context3D->pixelStorei(GraphicsContext3D::UNPACK_ROW_LENGTH, 0); + m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_ROWS, 0); + m_context3D->pixelStorei(GraphicsContext3D::UNPACK_SKIP_PIXELS, 0); + } +} + +void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag) +{ + m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); + + const unsigned bytesPerPixel = 4; + char* data = reinterpret_cast<char*>(const_cast<void*>(srcData)); + Vector<char> temporaryData; + IntPoint adjustedSourceOffset = sourceOffset; + + // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload. + bool requireSubImageBuffer = !driverSupportsSubImage(m_context3D.get()) + && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero()); + + // prepare temporaryData if necessary + if ((m_format == GraphicsContext3D::RGBA && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) { + temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel); + data = temporaryData.data(); + const char* bits = static_cast<const char*>(srcData); + const char* src = bits + sourceOffset.y() * bytesPerLine + sourceOffset.x() * bytesPerPixel; + char* dst = data; + const int targetBytesPerLine = targetRect.width() * bytesPerPixel; + for (int y = 0; y < targetRect.height(); ++y) { + memcpy(dst, src, targetBytesPerLine); + src += bytesPerLine; + dst += targetBytesPerLine; + } + + bytesPerLine = targetBytesPerLine; + adjustedSourceOffset = IntPoint(0, 0); + } + + if (m_format == GraphicsContext3D::RGBA) + swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel); + + updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, m_format); +} + +void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag) +{ + if (!image) + return; + NativeImagePtr frameImage = image->nativeImageForCurrentFrame(); + if (!frameImage) + return; + + int bytesPerLine; + const char* imageData; + +#if USE(CAIRO) + cairo_surface_t* surface = frameImage.get(); + imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface)); + bytesPerLine = cairo_image_surface_get_stride(surface); +#endif + + updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag); +} + +static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type) +{ + switch (type) { + case FilterOperation::GRAYSCALE: + case FilterOperation::SEPIA: + case FilterOperation::SATURATE: + case FilterOperation::HUE_ROTATE: + case FilterOperation::INVERT: + case FilterOperation::BRIGHTNESS: + case FilterOperation::CONTRAST: + case FilterOperation::OPACITY: + return 1; + case FilterOperation::BLUR: + case FilterOperation::DROP_SHADOW: + // We use two-passes (vertical+horizontal) for blur and drop-shadow. + return 2; + default: + return 0; + } +} + +PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper& textureMapper, const FilterOperations& filters) +{ + if (filters.isEmpty()) + return this; + + TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper); + RefPtr<BitmapTexture> previousSurface = texmapGL.currentSurface(); + RefPtr<BitmapTexture> resultSurface = this; + RefPtr<BitmapTexture> intermediateSurface; + RefPtr<BitmapTexture> spareSurface; + + m_filterInfo = FilterInfo(); + + for (size_t i = 0; i < filters.size(); ++i) { + RefPtr<FilterOperation> filter = filters.operations()[i]; + ASSERT(filter); + + int numPasses = getPassesRequiredForFilter(filter->type()); + for (int j = 0; j < numPasses; ++j) { + bool last = (i == filters.size() - 1) && (j == numPasses - 1); + if (!last) { + if (!intermediateSurface) + intermediateSurface = texmapGL.acquireTextureFromPool(contentSize(), BitmapTexture::SupportsAlpha | BitmapTexture::FBOAttachment); + texmapGL.bindSurface(intermediateSurface.get()); + } + + if (last) { + toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter, j, spareSurface); + break; + } + + texmapGL.drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j); + if (!j && filter->type() == FilterOperation::DROP_SHADOW) { + spareSurface = resultSurface; + resultSurface = nullptr; + } + std::swap(resultSurface, intermediateSurface); + } + } + + texmapGL.bindSurface(previousSurface.get()); + return resultSurface; +} + +void BitmapTextureGL::initializeStencil() +{ + if (m_rbo) + return; + + m_rbo = m_context3D->createRenderbuffer(); + m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_rbo); + m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_textureSize.width(), m_textureSize.height()); + m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); + m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_rbo); + m_context3D->clearStencil(0); + m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT); +} + +void BitmapTextureGL::initializeDepthBuffer() +{ + if (m_depthBufferObject) + return; + + m_depthBufferObject = m_context3D->createRenderbuffer(); + m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBufferObject); + m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_textureSize.width(), m_textureSize.height()); + m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); + m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBufferObject); +} + +void BitmapTextureGL::clearIfNeeded() +{ + if (!m_shouldClear) + return; + + m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), ClipStack::YAxisMode::Default); + m_clipStack.applyIfNeeded(*m_context3D); + m_context3D->clearColor(0, 0, 0, 0); + m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT); + m_shouldClear = false; +} + +void BitmapTextureGL::createFboIfNeeded() +{ + if (m_fbo) + return; + + m_fbo = m_context3D->createFramebuffer(); + m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); + m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, id(), 0); + m_shouldClear = true; +} + +void BitmapTextureGL::bindAsSurface(GraphicsContext3D* context3D) +{ + context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); + createFboIfNeeded(); + context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); + context3D->viewport(0, 0, m_textureSize.width(), m_textureSize.height()); + clearIfNeeded(); + m_clipStack.apply(*m_context3D); +} + +BitmapTextureGL::~BitmapTextureGL() +{ + if (m_id) + m_context3D->deleteTexture(m_id); + + if (m_fbo) + m_context3D->deleteFramebuffer(m_fbo); + + if (m_rbo) + m_context3D->deleteRenderbuffer(m_rbo); + + if (m_depthBufferObject) + m_context3D->deleteRenderbuffer(m_depthBufferObject); +} + +bool BitmapTextureGL::isValid() const +{ + return m_id; +} + +IntSize BitmapTextureGL::size() const +{ + return m_textureSize; +} + +}; // namespace WebCore + +#endif // USE(TEXTURE_MAPPER_GL) diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.h b/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.h new file mode 100644 index 000000000..c4a80224a --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTextureGL.h @@ -0,0 +1,114 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2014 Igalia S.L. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef BitmapTextureGL_h +#define BitmapTextureGL_h + +#if USE(TEXTURE_MAPPER_GL) + +#include "BitmapTexture.h" +#include "ClipStack.h" +#include "FilterOperation.h" +#include "GraphicsContext3D.h" +#include "IntSize.h" +#include "TextureMapperGL.h" + +namespace WebCore { + +class TextureMapper; +class TextureMapperGL; +class FilterOperation; + +class BitmapTextureGL : public BitmapTexture { +public: + static Ref<BitmapTexture> create(Ref<GraphicsContext3D>&& context3D, const Flags flags = NoFlag) + { + return adoptRef(*new BitmapTextureGL(WTFMove(context3D), flags)); + } + + virtual ~BitmapTextureGL(); + + IntSize size() const override; + bool isValid() const override; + void didReset() override; + void bindAsSurface(GraphicsContext3D*); + void initializeStencil(); + void initializeDepthBuffer(); + virtual uint32_t id() const { return m_id; } + uint32_t textureTarget() const { return GraphicsContext3D::TEXTURE_2D; } + IntSize textureSize() const { return m_textureSize; } + void updateContents(Image*, const IntRect&, const IntPoint&, UpdateContentsFlag) override; + void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag) override; + void updateContentsNoSwizzle(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel = 4, Platform3DObject glFormat = GraphicsContext3D::RGBA); + bool isBackedByOpenGL() const override { return true; } + + PassRefPtr<BitmapTexture> applyFilters(TextureMapper&, const FilterOperations&) override; + struct FilterInfo { + RefPtr<FilterOperation> filter; + unsigned pass; + RefPtr<BitmapTexture> contentTexture; + + FilterInfo(PassRefPtr<FilterOperation> f = 0, unsigned p = 0, PassRefPtr<BitmapTexture> t = 0) + : filter(f) + , pass(p) + , contentTexture(t) + { } + }; + const FilterInfo* filterInfo() const { return &m_filterInfo; } + ClipStack& clipStack() { return m_clipStack; } + + GC3Dint internalFormat() const { return m_internalFormat; } + +private: + BitmapTextureGL(RefPtr<GraphicsContext3D>&&, const Flags); + + Platform3DObject m_id { 0 }; + IntSize m_textureSize; + IntRect m_dirtyRect; + Platform3DObject m_fbo { 0 }; + Platform3DObject m_rbo { 0 }; + Platform3DObject m_depthBufferObject { 0 }; + bool m_shouldClear { true }; + ClipStack m_clipStack; + RefPtr<GraphicsContext3D> m_context3D; + + void clearIfNeeded(); + void createFboIfNeeded(); + + FilterInfo m_filterInfo; + + GC3Dint m_internalFormat; + GC3Denum m_format; + GC3Denum m_type { +#if OS(DARWIN) + GL_UNSIGNED_INT_8_8_8_8_REV +#else + GraphicsContext3D::UNSIGNED_BYTE +#endif + }; +}; + +BitmapTextureGL* toBitmapTextureGL(BitmapTexture*); + +} + +#endif // USE(TEXTURE_MAPPER_GL) + +#endif // BitmapTextureGL_h diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp new file mode 100644 index 000000000..00cc8ee36 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" +#include "BitmapTexturePool.h" + +#if USE(TEXTURE_MAPPER_GL) +#include "BitmapTextureGL.h" +#endif + +namespace WebCore { + +static const double s_releaseUnusedSecondsTolerance = 3; +static const double s_releaseUnusedTexturesTimerInterval = 0.5; + +#if USE(TEXTURE_MAPPER_GL) +BitmapTexturePool::BitmapTexturePool(RefPtr<GraphicsContext3D>&& context3D) + : m_context3D(WTFMove(context3D)) + , m_releaseUnusedTexturesTimer(*this, &BitmapTexturePool::releaseUnusedTexturesTimerFired) +{ +} +#endif + +RefPtr<BitmapTexture> BitmapTexturePool::acquireTexture(const IntSize& size, const BitmapTexture::Flags flags) +{ + Vector<Entry>& list = flags & BitmapTexture::FBOAttachment ? m_attachmentTextures : m_textures; + + Entry* selectedEntry = std::find_if(list.begin(), list.end(), + [&size](Entry& entry) { return entry.m_texture->refCount() == 1 && entry.m_texture->size() == size; }); + + if (selectedEntry == list.end()) { + list.append(Entry(createTexture(flags))); + selectedEntry = &list.last(); + } + + scheduleReleaseUnusedTextures(); + selectedEntry->markIsInUse(); + return selectedEntry->m_texture.copyRef(); +} + +void BitmapTexturePool::scheduleReleaseUnusedTextures() +{ + if (m_releaseUnusedTexturesTimer.isActive()) + return; + + m_releaseUnusedTexturesTimer.startOneShot(s_releaseUnusedTexturesTimerInterval); +} + +void BitmapTexturePool::releaseUnusedTexturesTimerFired() +{ + // Delete entries, which have been unused in s_releaseUnusedSecondsTolerance. + double minUsedTime = monotonicallyIncreasingTime() - s_releaseUnusedSecondsTolerance; + + if (!m_textures.isEmpty()) { + std::sort(m_textures.begin(), m_textures.end(), + [](const Entry& a, const Entry& b) { return a.m_lastUsedTime > b.m_lastUsedTime; }); + + for (size_t i = 0; i < m_textures.size(); ++i) { + if (m_textures[i].m_lastUsedTime < minUsedTime) { + m_textures.remove(i, m_textures.size() - i); + break; + } + } + } + + if (!m_attachmentTextures.isEmpty()) { + std::sort(m_attachmentTextures.begin(), m_attachmentTextures.end(), + [](const Entry& a, const Entry& b) { return a.m_lastUsedTime > b.m_lastUsedTime; }); + + for (size_t i = 0; i < m_attachmentTextures.size(); ++i) { + if (m_attachmentTextures[i].m_lastUsedTime < minUsedTime) { + m_attachmentTextures.remove(i, m_attachmentTextures.size() - i); + break; + } + } + } + + if (!m_textures.isEmpty() || !m_attachmentTextures.isEmpty()) + scheduleReleaseUnusedTextures(); +} + +RefPtr<BitmapTexture> BitmapTexturePool::createTexture(const BitmapTexture::Flags flags) +{ +#if USE(TEXTURE_MAPPER_GL) + return BitmapTextureGL::create(*m_context3D, flags); +#else + return nullptr; +#endif +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h new file mode 100644 index 000000000..5c740fc10 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/BitmapTexturePool.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2014 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 BitmapTexturePool_h +#define BitmapTexturePool_h + +#include "BitmapTexture.h" +#include "Timer.h" +#include <wtf/CurrentTime.h> + +#if USE(TEXTURE_MAPPER_GL) +#include "GraphicsContext3D.h" +#endif + +namespace WebCore { + +class GraphicsContext3D; +class IntSize; + +class BitmapTexturePool { + WTF_MAKE_NONCOPYABLE(BitmapTexturePool); + WTF_MAKE_FAST_ALLOCATED; +public: +#if USE(TEXTURE_MAPPER_GL) + explicit BitmapTexturePool(RefPtr<GraphicsContext3D>&&); +#endif + + RefPtr<BitmapTexture> acquireTexture(const IntSize&, const BitmapTexture::Flags); + +private: + struct Entry { + explicit Entry(RefPtr<BitmapTexture>&& texture) + : m_texture(WTFMove(texture)) + { } + + void markIsInUse() { m_lastUsedTime = monotonicallyIncreasingTime(); } + + RefPtr<BitmapTexture> m_texture; + double m_lastUsedTime { 0.0 }; + }; + + void scheduleReleaseUnusedTextures(); + void releaseUnusedTexturesTimerFired(); + RefPtr<BitmapTexture> createTexture(const BitmapTexture::Flags); + +#if USE(TEXTURE_MAPPER_GL) + RefPtr<GraphicsContext3D> m_context3D; +#endif + + Vector<Entry> m_textures; + Vector<Entry> m_attachmentTextures; + Timer m_releaseUnusedTexturesTimer; +}; + +} // namespace WebCore + +#endif // BitmapTexturePool_h diff --git a/Source/WebCore/platform/graphics/texmap/ClipStack.cpp b/Source/WebCore/platform/graphics/texmap/ClipStack.cpp new file mode 100644 index 000000000..11a00bc8a --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/ClipStack.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2012 Adobe Systems Incorporated + * Copyright (C) 2012, 2016 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "ClipStack.h" + +#include "GraphicsContext3D.h" + +namespace WebCore { + +void ClipStack::push() +{ + clipStack.append(clipState); + clipStateDirty = true; +} + +void ClipStack::pop() +{ + if (clipStack.isEmpty()) + return; + clipState = clipStack.last(); + clipStack.removeLast(); + clipStateDirty = true; +} + +void ClipStack::reset(const IntRect& rect, ClipStack::YAxisMode mode) +{ + clipStack.clear(); + size = rect.size(); + yAxisMode = mode; + clipState = State(rect); + clipStateDirty = true; +} + +void ClipStack::intersect(const IntRect& rect) +{ + clipState.scissorBox.intersect(rect); + clipStateDirty = true; +} + +void ClipStack::setStencilIndex(int stencilIndex) +{ + clipState.stencilIndex = stencilIndex; + clipStateDirty = true; +} + +void ClipStack::apply(GraphicsContext3D& context) +{ + if (clipState.scissorBox.isEmpty()) + return; + + context.scissor(clipState.scissorBox.x(), + (yAxisMode == YAxisMode::Inverted) ? size.height() - clipState.scissorBox.maxY() : clipState.scissorBox.y(), + clipState.scissorBox.width(), clipState.scissorBox.height()); + context.stencilOp(GraphicsContext3D::KEEP, GraphicsContext3D::KEEP, GraphicsContext3D::KEEP); + context.stencilFunc(GraphicsContext3D::EQUAL, clipState.stencilIndex - 1, clipState.stencilIndex - 1); + if (clipState.stencilIndex == 1) + context.disable(GraphicsContext3D::STENCIL_TEST); + else + context.enable(GraphicsContext3D::STENCIL_TEST); +} + +void ClipStack::applyIfNeeded(GraphicsContext3D& context) +{ + if (!clipStateDirty) + return; + + clipStateDirty = false; + apply(context); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/texmap/ClipStack.h b/Source/WebCore/platform/graphics/texmap/ClipStack.h new file mode 100644 index 000000000..2fc40475b --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/ClipStack.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2015, 2016 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ClipStack_h +#define ClipStack_h + +#include "IntRect.h" +#include "IntSize.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class GraphicsContext3D; + +class ClipStack { +public: + struct State { + State(const IntRect& scissors = IntRect(), int stencil = 1) + : scissorBox(scissors) + , stencilIndex(stencil) + { } + + IntRect scissorBox; + int stencilIndex; + }; + + // Y-axis should be inverted only when painting into the window. + enum class YAxisMode { + Default, + Inverted, + }; + + void push(); + void pop(); + State& current() { return clipState; } + + void reset(const IntRect&, YAxisMode); + void intersect(const IntRect&); + void setStencilIndex(int); + int getStencilIndex() const { return clipState.stencilIndex; } + + void apply(GraphicsContext3D&); + void applyIfNeeded(GraphicsContext3D&); + + bool isCurrentScissorBoxEmpty() const { return clipState.scissorBox.isEmpty(); } + +private: + Vector<State> clipStack; + State clipState; + IntSize size; + bool clipStateDirty { false }; + YAxisMode yAxisMode { YAxisMode::Default }; +}; + +} // namespace WebCore + +#endif // ClipStack_h diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp index 1b87ee626..78a0246f7 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -21,31 +21,25 @@ #include "GraphicsLayerTextureMapper.h" #include "GraphicsContext.h" -#include "GraphicsLayerAnimation.h" #include "GraphicsLayerFactory.h" #include "ImageBuffer.h" +#include "TextureMapperAnimation.h" #include <wtf/CurrentTime.h> -#if USE(TEXTURE_MAPPER) +#if !USE(COORDINATED_GRAPHICS) namespace WebCore { -TextureMapperLayer* toTextureMapperLayer(GraphicsLayer* layer) -{ - return layer ? toGraphicsLayerTextureMapper(layer)->layer() : 0; -} - -std::unique_ptr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient* client) +std::unique_ptr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient& client, Type layerType) { if (!factory) - return std::make_unique<GraphicsLayerTextureMapper>(client); + return std::make_unique<GraphicsLayerTextureMapper>(layerType, client); - return factory->createGraphicsLayer(client); + return factory->createGraphicsLayer(layerType, client); } -GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* client) - : GraphicsLayer(client) - , m_layer(adoptPtr(new TextureMapperLayer())) +GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(Type layerType, GraphicsLayerClient& client) + : GraphicsLayer(layerType, client) , m_compositedNativeImagePtr(0) , m_changeMask(NoChanges) , m_needsDisplay(false) @@ -59,15 +53,11 @@ GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* clie void GraphicsLayerTextureMapper::notifyChange(ChangeMask changeMask) { + bool flushRequired = m_changeMask == NoChanges; m_changeMask |= changeMask; - if (!client()) - return; - client()->notifyFlushRequired(this); -} -void GraphicsLayerTextureMapper::setName(const String& name) -{ - GraphicsLayer::setName(name); + if (flushRequired) + client().notifyFlushRequired(this); } GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper() @@ -78,33 +68,23 @@ GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper() willBeDestroyed(); } -void GraphicsLayerTextureMapper::willBeDestroyed() -{ - GraphicsLayer::willBeDestroyed(); -} - -/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display. -*/ void GraphicsLayerTextureMapper::setNeedsDisplay() { if (!drawsContent()) return; + // The current size might change, thus we need to update the whole display. m_needsDisplay = true; notifyChange(DisplayChange); addRepaintRect(FloatRect(FloatPoint(), m_size)); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setContentsNeedsDisplay() { notifyChange(DisplayChange); addRepaintRect(contentsRect()); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect, ShouldClipToLayer) { if (!drawsContent()) @@ -117,8 +97,6 @@ void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect, Sh addRepaintRect(rect); } -/* \reimp (GraphicsLayer.h) -*/ bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& children) { if (GraphicsLayer::setChildren(children)) { @@ -128,40 +106,30 @@ bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& child return false; } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer) { notifyChange(ChildrenChange); GraphicsLayer::addChild(layer); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::addChildAtIndex(GraphicsLayer* layer, int index) { GraphicsLayer::addChildAtIndex(layer, index); notifyChange(ChildrenChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling) { GraphicsLayer::addChildAbove(layer, sibling); notifyChange(ChildrenChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling) { GraphicsLayer::addChildBelow(layer, sibling); notifyChange(ChildrenChange); } -/* \reimp (GraphicsLayer.h) -*/ bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) { if (GraphicsLayer::replaceChild(oldChild, newChild)) { @@ -171,8 +139,6 @@ bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsL return false; } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value) { if (value == maskLayer()) @@ -187,8 +153,6 @@ void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value) } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value) { if (value == replicaLayer()) @@ -197,8 +161,6 @@ void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value) notifyChange(ReplicaLayerChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value) { if (value == position()) @@ -207,8 +169,6 @@ void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value) notifyChange(PositionChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value) { if (value == anchorPoint()) @@ -217,8 +177,6 @@ void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value) notifyChange(AnchorPointChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setSize(const FloatSize& value) { if (value == size()) @@ -230,8 +188,6 @@ void GraphicsLayerTextureMapper::setSize(const FloatSize& value) notifyChange(SizeChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value) { if (value == transform()) @@ -241,8 +197,6 @@ void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value) notifyChange(TransformChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix& value) { if (value == childrenTransform()) @@ -251,8 +205,6 @@ void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix notifyChange(ChildrenTransformChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setPreserves3D(bool value) { if (value == preserves3D()) @@ -261,8 +213,6 @@ void GraphicsLayerTextureMapper::setPreserves3D(bool value) notifyChange(Preserves3DChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setMasksToBounds(bool value) { if (value == masksToBounds()) @@ -271,8 +221,6 @@ void GraphicsLayerTextureMapper::setMasksToBounds(bool value) notifyChange(MasksToBoundsChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setDrawsContent(bool value) { if (value == drawsContent()) @@ -284,8 +232,6 @@ void GraphicsLayerTextureMapper::setDrawsContent(bool value) setNeedsDisplay(); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setContentsVisible(bool value) { if (value == contentsAreVisible()) @@ -296,8 +242,6 @@ void GraphicsLayerTextureMapper::setContentsVisible(bool value) maskLayer()->setContentsVisible(value); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setContentsOpaque(bool value) { if (value == contentsOpaque()) @@ -306,8 +250,6 @@ void GraphicsLayerTextureMapper::setContentsOpaque(bool value) GraphicsLayer::setContentsOpaque(value); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value) { if (value == backfaceVisibility()) @@ -316,8 +258,6 @@ void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value) notifyChange(BackfaceVisibilityChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setOpacity(float value) { if (value == opacity()) @@ -326,9 +266,7 @@ void GraphicsLayerTextureMapper::setOpacity(float value) notifyChange(OpacityChange); } -/* \reimp (GraphicsLayer.h) -*/ -void GraphicsLayerTextureMapper::setContentsRect(const IntRect& value) +void GraphicsLayerTextureMapper::setContentsRect(const FloatRect& value) { if (value == contentsRect()) return; @@ -345,15 +283,12 @@ void GraphicsLayerTextureMapper::setContentsToSolidColor(const Color& color) notifyChange(BackgroundColorChange); } - -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::setContentsToImage(Image* image) { if (image) { // Make the decision about whether the image has changed. // This code makes the assumption that pointer equality on a NativeImagePtr is a valid way to tell if the image is changed. - // This assumption is true in Qt, GTK and EFL. + // This assumption is true for the GTK+ port. NativeImagePtr newNativeImagePtr = image->nativeImageForCurrentFrame(); if (!newNativeImagePtr) return; @@ -365,28 +300,29 @@ void GraphicsLayerTextureMapper::setContentsToImage(Image* image) if (!m_compositedImage) m_compositedImage = TextureMapperTiledBackingStore::create(); m_compositedImage->setContentsToImage(image); + m_compositedImage->updateContentsScale(pageScaleFactor() * deviceScaleFactor()); } else { - m_compositedNativeImagePtr = 0; - m_compositedImage = 0; + m_compositedNativeImagePtr = nullptr; + m_compositedImage = nullptr; } - setContentsToMedia(m_compositedImage.get()); + setContentsToPlatformLayer(m_compositedImage.get(), ContentsLayerForImage); notifyChange(ContentChange); GraphicsLayer::setContentsToImage(image); } -void GraphicsLayerTextureMapper::setContentsToMedia(TextureMapperPlatformLayer* media) +void GraphicsLayerTextureMapper::setContentsToPlatformLayer(TextureMapperPlatformLayer* platformLayer, ContentsLayerPurpose purpose) { - if (media == m_contentsLayer) + if (platformLayer == m_contentsLayer) return; - GraphicsLayer::setContentsToMedia(media); + GraphicsLayer::setContentsToPlatformLayer(platformLayer, purpose); notifyChange(ContentChange); if (m_contentsLayer) m_contentsLayer->setClient(0); - m_contentsLayer = media; + m_contentsLayer = platformLayer; if (m_contentsLayer) m_contentsLayer->setClient(this); @@ -428,26 +364,25 @@ void GraphicsLayerTextureMapper::setIsScrollable(bool isScrollable) notifyChange(IsScrollableChange); } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::flushCompositingStateForThisLayerOnly() { prepareBackingStoreIfNeeded(); commitLayerChanges(); - m_layer->syncAnimations(); - updateBackingStoreIfNeeded(); + m_layer.syncAnimations(); } void GraphicsLayerTextureMapper::prepareBackingStoreIfNeeded() { - if (!shouldHaveBackingStore()) { - m_backingStore.clear(); - m_changeMask |= BackingStoreChange; - } else { + if (shouldHaveBackingStore()) { if (!m_backingStore) { m_backingStore = TextureMapperTiledBackingStore::create(); m_changeMask |= BackingStoreChange; } + } else { + if (m_backingStore) { + m_backingStore = nullptr; + m_changeMask |= BackingStoreChange; + } } updateDebugBorderAndRepaintCount(); @@ -473,112 +408,98 @@ void GraphicsLayerTextureMapper::setDebugBorder(const Color& color, float width) m_changeMask |= DebugVisualsChange; } -static void toTextureMapperLayerVector(const Vector<GraphicsLayer*>& layers, Vector<TextureMapperLayer*>& texmapLayers) -{ - texmapLayers.reserveCapacity(layers.size()); - for (size_t i = 0; i < layers.size(); ++i) - texmapLayers.append(toTextureMapperLayer(layers[i])); -} - void GraphicsLayerTextureMapper::commitLayerChanges() { if (m_changeMask == NoChanges) return; - if (m_changeMask & ChildrenChange) { - Vector<TextureMapperLayer*> textureMapperLayerChildren; - toTextureMapperLayerVector(children(), textureMapperLayerChildren); - m_layer->setChildren(textureMapperLayerChildren); - } + if (m_changeMask & ChildrenChange) + m_layer.setChildren(children()); if (m_changeMask & MaskLayerChange) - m_layer->setMaskLayer(toTextureMapperLayer(maskLayer())); + m_layer.setMaskLayer(&downcast<GraphicsLayerTextureMapper>(maskLayer())->layer()); if (m_changeMask & ReplicaLayerChange) - m_layer->setReplicaLayer(toTextureMapperLayer(replicaLayer())); + m_layer.setReplicaLayer(&downcast<GraphicsLayerTextureMapper>(replicaLayer())->layer()); if (m_changeMask & PositionChange) - m_layer->setPosition(position()); + m_layer.setPosition(position()); if (m_changeMask & AnchorPointChange) - m_layer->setAnchorPoint(anchorPoint()); + m_layer.setAnchorPoint(anchorPoint()); if (m_changeMask & SizeChange) - m_layer->setSize(size()); + m_layer.setSize(size()); if (m_changeMask & TransformChange) - m_layer->setTransform(transform()); + m_layer.setTransform(transform()); if (m_changeMask & ChildrenTransformChange) - m_layer->setChildrenTransform(childrenTransform()); + m_layer.setChildrenTransform(childrenTransform()); if (m_changeMask & Preserves3DChange) - m_layer->setPreserves3D(preserves3D()); + m_layer.setPreserves3D(preserves3D()); if (m_changeMask & ContentsRectChange) - m_layer->setContentsRect(contentsRect()); + m_layer.setContentsRect(contentsRect()); if (m_changeMask & MasksToBoundsChange) - m_layer->setMasksToBounds(masksToBounds()); + m_layer.setMasksToBounds(masksToBounds()); if (m_changeMask & DrawsContentChange) - m_layer->setDrawsContent(drawsContent()); + m_layer.setDrawsContent(drawsContent()); if (m_changeMask & ContentsVisibleChange) - m_layer->setContentsVisible(contentsAreVisible()); + m_layer.setContentsVisible(contentsAreVisible()); if (m_changeMask & ContentsOpaqueChange) - m_layer->setContentsOpaque(contentsOpaque()); + m_layer.setContentsOpaque(contentsOpaque()); if (m_changeMask & BackfaceVisibilityChange) - m_layer->setBackfaceVisibility(backfaceVisibility()); + m_layer.setBackfaceVisibility(backfaceVisibility()); if (m_changeMask & OpacityChange) - m_layer->setOpacity(opacity()); + m_layer.setOpacity(opacity()); if (m_changeMask & BackgroundColorChange) - m_layer->setSolidColor(solidColor()); + m_layer.setSolidColor(m_solidColor); -#if ENABLE(CSS_FILTERS) if (m_changeMask & FilterChange) - m_layer->setFilters(filters()); -#endif + m_layer.setFilters(filters()); if (m_changeMask & BackingStoreChange) - m_layer->setBackingStore(m_backingStore); + m_layer.setBackingStore(m_backingStore); if (m_changeMask & DebugVisualsChange) - m_layer->setDebugVisuals(isShowingDebugBorder(), debugBorderColor(), debugBorderWidth(), isShowingRepaintCounter()); + m_layer.setDebugVisuals(isShowingDebugBorder(), debugBorderColor(), debugBorderWidth(), isShowingRepaintCounter()); if (m_changeMask & RepaintCountChange) - m_layer->setRepaintCount(repaintCount()); + m_layer.setRepaintCount(repaintCount()); if (m_changeMask & ContentChange) - m_layer->setContentsLayer(platformLayer()); + m_layer.setContentsLayer(platformLayer()); if (m_changeMask & AnimationChange) - m_layer->setAnimations(m_animations); + m_layer.setAnimations(m_animations); if (m_changeMask & AnimationStarted) - client()->notifyAnimationStarted(this, m_animationStartTime); + client().notifyAnimationStarted(this, "", m_animationStartTime); if (m_changeMask & FixedToViewporChange) - m_layer->setFixedToViewport(fixedToViewport()); + m_layer.setFixedToViewport(fixedToViewport()); if (m_changeMask & IsScrollableChange) - m_layer->setIsScrollable(isScrollable()); + m_layer.setIsScrollable(isScrollable()); if (m_changeMask & CommittedScrollOffsetChange) - m_layer->didCommitScrollOffset(m_committedScrollOffset); + m_layer.didCommitScrollOffset(m_committedScrollOffset); m_changeMask = NoChanges; } -/* \reimp (GraphicsLayer.h) -*/ void GraphicsLayerTextureMapper::flushCompositingState(const FloatRect& rect) { - if (!m_layer->textureMapper()) + if (!m_layer.textureMapper()) return; flushCompositingStateForThisLayerOnly(); @@ -587,13 +508,28 @@ void GraphicsLayerTextureMapper::flushCompositingState(const FloatRect& rect) maskLayer()->flushCompositingState(rect); if (replicaLayer()) replicaLayer()->flushCompositingState(rect); - for (size_t i = 0; i < children().size(); ++i) - children()[i]->flushCompositingState(rect); + for (auto* child : children()) + child->flushCompositingState(rect); +} + +void GraphicsLayerTextureMapper::updateBackingStoreIncludingSubLayers() +{ + if (!m_layer.textureMapper()) + return; + + updateBackingStoreIfNeeded(); + + if (maskLayer()) + downcast<GraphicsLayerTextureMapper>(*maskLayer()).updateBackingStoreIfNeeded(); + if (replicaLayer()) + downcast<GraphicsLayerTextureMapper>(*replicaLayer()).updateBackingStoreIfNeeded(); + for (auto* child : children()) + downcast<GraphicsLayerTextureMapper>(*child).updateBackingStoreIncludingSubLayers(); } void GraphicsLayerTextureMapper::updateBackingStoreIfNeeded() { - TextureMapper* textureMapper = m_layer->textureMapper(); + TextureMapper* textureMapper = m_layer.textureMapper(); if (!textureMapper) return; @@ -610,8 +546,10 @@ void GraphicsLayerTextureMapper::updateBackingStoreIfNeeded() return; TextureMapperTiledBackingStore* backingStore = static_cast<TextureMapperTiledBackingStore*>(m_backingStore.get()); + backingStore->updateContentsScale(pageScaleFactor() * deviceScaleFactor()); - backingStore->updateContents(textureMapper, this, m_size, dirtyRect, BitmapTexture::UpdateCanModifyOriginalImageData); + dirtyRect.scale(pageScaleFactor() * deviceScaleFactor()); + backingStore->updateContents(*textureMapper, this, m_size, dirtyRect, BitmapTexture::UpdateCanModifyOriginalImageData); m_needsDisplay = false; m_needsDisplayRect = IntRect(); @@ -622,21 +560,44 @@ bool GraphicsLayerTextureMapper::shouldHaveBackingStore() const return drawsContent() && contentsAreVisible() && !m_size.isEmpty(); } -bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) +bool GraphicsLayerTextureMapper::filtersCanBeComposited(const FilterOperations& filters) const +{ + if (!filters.size()) + return false; + + for (const auto& filterOperation : filters.operations()) { + if (filterOperation->type() == FilterOperation::REFERENCE) + return false; + } + + return true; +} + +bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) { ASSERT(!keyframesName.isEmpty()); - if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyWebkitTransform && valueList.property() != AnimatedPropertyOpacity)) + if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyTransform && valueList.property() != AnimatedPropertyOpacity)) return false; + if (valueList.property() == AnimatedPropertyFilter) { + int listIndex = validateFilterOperations(valueList); + if (listIndex < 0) + return false; + + const auto& filters = static_cast<const FilterAnimationValue&>(valueList.at(listIndex)).value(); + if (!filtersCanBeComposited(filters)) + return false; + } + bool listsMatch = false; bool hasBigRotation; - if (valueList.property() == AnimatedPropertyWebkitTransform) + if (valueList.property() == AnimatedPropertyTransform) listsMatch = validateTransformOperations(valueList, hasBigRotation) >= 0; const double currentTime = monotonicallyIncreasingTime(); - m_animations.add(GraphicsLayerAnimation(keyframesName, valueList, boxSize, anim, currentTime - timeOffset, listsMatch)); + m_animations.add(TextureMapperAnimation(keyframesName, valueList, boxSize, *anim, listsMatch, currentTime - timeOffset, 0, TextureMapperAnimation::AnimationState::Playing)); // m_animationStartTime is the time of the first real frame of animation, now or delayed by a negative offset. if (timeOffset > 0) m_animationStartTime = currentTime; @@ -647,7 +608,7 @@ bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList return true; } -void GraphicsLayerTextureMapper::setAnimations(const GraphicsLayerAnimations& animations) +void GraphicsLayerTextureMapper::setAnimations(const TextureMapperAnimations& animations) { m_animations = animations; notifyChange(AnimationChange); @@ -664,17 +625,26 @@ void GraphicsLayerTextureMapper::removeAnimation(const String& animationName) m_animations.remove(animationName); } -#if ENABLE(CSS_FILTERS) bool GraphicsLayerTextureMapper::setFilters(const FilterOperations& filters) { - TextureMapper* textureMapper = m_layer->textureMapper(); - // TextureMapperImageBuffer does not support CSS filters. - if (!textureMapper || textureMapper->accelerationMode() == TextureMapper::SoftwareMode) + if (!m_layer.textureMapper()) return false; - notifyChange(FilterChange); - return GraphicsLayer::setFilters(filters); + + bool canCompositeFilters = filtersCanBeComposited(filters); + if (GraphicsLayer::filters() == filters) + return canCompositeFilters; + + if (canCompositeFilters) { + if (!GraphicsLayer::setFilters(filters)) + return false; + notifyChange(FilterChange); + } else if (GraphicsLayer::filters().size()) { + clearFilters(); + notifyChange(FilterChange); + } + + return canCompositeFilters; } -#endif void GraphicsLayerTextureMapper::setFixedToViewport(bool fixed) { diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h index e3340d346..42ed713d3 100644 --- a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -20,7 +20,7 @@ #ifndef GraphicsLayerTextureMapper_h #define GraphicsLayerTextureMapper_h -#if USE(TEXTURE_MAPPER) +#if !USE(COORDINATED_GRAPHICS) #include "GraphicsLayer.h" #include "GraphicsLayerClient.h" @@ -32,70 +32,68 @@ namespace WebCore { -class GraphicsLayerTextureMapper : public GraphicsLayer, public TextureMapperPlatformLayer::Client { +class GraphicsLayerTextureMapper final : public GraphicsLayer, TextureMapperPlatformLayer::Client { public: - explicit GraphicsLayerTextureMapper(GraphicsLayerClient*); + explicit GraphicsLayerTextureMapper(Type, GraphicsLayerClient&); virtual ~GraphicsLayerTextureMapper(); - void setScrollClient(TextureMapperLayer::ScrollingClient* client) { m_layer->setScrollClient(client); } - void setID(uint32_t id) { m_layer->setID(id); } - - // reimps from GraphicsLayer.h - virtual void setNeedsDisplay(); - virtual void setContentsNeedsDisplay(); - virtual void setNeedsDisplayInRect(const FloatRect&, ShouldClipToLayer = ClipToLayer); - virtual bool setChildren(const Vector<GraphicsLayer*>&); - virtual void addChild(GraphicsLayer*); - virtual void addChildAtIndex(GraphicsLayer*, int index); - virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); - virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling); - virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild); - virtual void setMaskLayer(GraphicsLayer* layer); - virtual void setPosition(const FloatPoint& p); - virtual void setAnchorPoint(const FloatPoint3D& p); - virtual void setSize(const FloatSize& size); - virtual void setTransform(const TransformationMatrix& t); - virtual void setChildrenTransform(const TransformationMatrix& t); - virtual void setPreserves3D(bool b); - virtual void setMasksToBounds(bool b); - virtual void setDrawsContent(bool b); - virtual void setContentsVisible(bool); - virtual void setContentsOpaque(bool b); - virtual void setBackfaceVisibility(bool b); - virtual void setOpacity(float opacity); - virtual void setContentsRect(const IntRect& r); - virtual void setReplicatedByLayer(GraphicsLayer*); - virtual void setContentsToImage(Image*); - virtual void setContentsToSolidColor(const Color&); - Color solidColor() const { return m_solidColor; } - virtual void setContentsToMedia(PlatformLayer*); - virtual void setContentsToCanvas(PlatformLayer* canvas) { setContentsToMedia(canvas); } - virtual void setShowDebugBorder(bool) override; - virtual void setDebugBorder(const Color&, float width) override; - virtual void setShowRepaintCounter(bool) override; - virtual void flushCompositingState(const FloatRect&); - virtual void flushCompositingStateForThisLayerOnly(); - virtual void setName(const String& name); - virtual bool hasContentsLayer() const { return m_contentsLayer; } - virtual PlatformLayer* platformLayer() const { return m_contentsLayer; } - - inline int changeMask() const { return m_changeMask; } - - virtual bool addAnimation(const KeyframeValueList&, const IntSize&, const Animation*, const String&, double); - virtual void pauseAnimation(const String&, double); - virtual void removeAnimation(const String&); - void setAnimations(const GraphicsLayerAnimations&); - - TextureMapperLayer* layer() const { return m_layer.get(); } + void setScrollClient(TextureMapperLayer::ScrollingClient* client) { m_layer.setScrollClient(client); } + void setID(uint32_t id) { m_layer.setID(id); } + + // GraphicsLayer + bool setChildren(const Vector<GraphicsLayer*>&) override; + void addChild(GraphicsLayer*) override; + void addChildAtIndex(GraphicsLayer*, int index) override; + void addChildAbove(GraphicsLayer*, GraphicsLayer* sibling) override; + void addChildBelow(GraphicsLayer*, GraphicsLayer* sibling) override; + bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) override; + + void setMaskLayer(GraphicsLayer*) override; + void setReplicatedByLayer(GraphicsLayer*) override; + void setPosition(const FloatPoint&) override; + void setAnchorPoint(const FloatPoint3D&) override; + void setSize(const FloatSize&) override; + void setTransform(const TransformationMatrix&) override; + void setChildrenTransform(const TransformationMatrix&) override; + void setPreserves3D(bool) override; + void setMasksToBounds(bool) override; + void setDrawsContent(bool) override; + void setContentsVisible(bool) override; + void setContentsOpaque(bool) override; + void setBackfaceVisibility(bool) override; + void setOpacity(float) override; + bool setFilters(const FilterOperations&) override; + + void setNeedsDisplay() override; + void setNeedsDisplayInRect(const FloatRect&, ShouldClipToLayer = ClipToLayer) override; + void setContentsNeedsDisplay() override; + void setContentsRect(const FloatRect&) override; + + bool addAnimation(const KeyframeValueList&, const FloatSize&, const Animation*, const String&, double) override; + void pauseAnimation(const String&, double) override; + void removeAnimation(const String&) override; + + void setContentsToImage(Image*) override; + void setContentsToSolidColor(const Color&) override; + void setContentsToPlatformLayer(PlatformLayer*, ContentsLayerPurpose) override; + bool usesContentsLayer() const override { return m_contentsLayer; } + PlatformLayer* platformLayer() const override { return m_contentsLayer; } + + void setShowDebugBorder(bool) override; + void setDebugBorder(const Color&, float width) override; + void setShowRepaintCounter(bool) override; + + void flushCompositingState(const FloatRect&) override; + void flushCompositingStateForThisLayerOnly() override; + + void updateBackingStoreIncludingSubLayers(); + + TextureMapperLayer& layer() { return m_layer; } void didCommitScrollOffset(const IntSize&); void setIsScrollable(bool); bool isScrollable() const { return m_isScrollable; } -#if ENABLE(CSS_FILTERS) - virtual bool setFilters(const FilterOperations&); -#endif - void setFixedToViewport(bool); bool fixedToViewport() const { return m_fixedToViewport; } @@ -103,8 +101,15 @@ public: float debugBorderWidth() const { return m_debugBorderWidth; } void setRepaintCount(int); + void setAnimations(const TextureMapperAnimations&); + private: - virtual void willBeDestroyed(); + // GraphicsLayer + bool isGraphicsLayerTextureMapper() const override { return true; } + + // TextureMapperPlatformLayer::Client + void platformLayerWillBeDestroyed() override { setContentsToPlatformLayer(0, NoContentsLayer); } + void setPlatformLayerNeedsDisplay() override { setContentsNeedsDisplay(); } void commitLayerChanges(); void updateDebugBorderAndRepaintCount(); @@ -112,8 +117,7 @@ private: void prepareBackingStoreIfNeeded(); bool shouldHaveBackingStore() const; - virtual void platformLayerWillBeDestroyed() override { setContentsToMedia(0); } - virtual void setPlatformLayerNeedsDisplay() override { setContentsNeedsDisplay(); } + bool filtersCanBeComposited(const FilterOperations&) const; // This set of flags help us defer which properties of the layer have been // modified by the compositor, so we can know what to look for in the next flush. @@ -160,7 +164,7 @@ private: }; void notifyChange(ChangeMask); - OwnPtr<TextureMapperLayer> m_layer; + TextureMapperLayer m_layer; RefPtr<TextureMapperTiledBackingStore> m_compositedImage; NativeImagePtr m_compositedNativeImagePtr; RefPtr<TextureMapperBackingStore> m_backingStore; @@ -175,21 +179,17 @@ private: TextureMapperPlatformLayer* m_contentsLayer; FloatRect m_needsDisplayRect; - GraphicsLayerAnimations m_animations; + TextureMapperAnimations m_animations; double m_animationStartTime; IntSize m_committedScrollOffset; bool m_isScrollable; }; -inline static GraphicsLayerTextureMapper* toGraphicsLayerTextureMapper(GraphicsLayer* layer) -{ - return static_cast<GraphicsLayerTextureMapper*>(layer); -} +} // namespace WebCore -TextureMapperLayer* toTextureMapperLayer(GraphicsLayer*); +SPECIALIZE_TYPE_TRAITS_GRAPHICSLAYER(WebCore::GraphicsLayerTextureMapper, isGraphicsLayerTextureMapper()) -} #endif #endif // GraphicsLayerTextureMapper_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp index b863e79e5..973047f49 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.cpp @@ -20,151 +20,28 @@ #include "config.h" #include "TextureMapper.h" +#include "BitmapTexturePool.h" #include "FilterOperations.h" #include "GraphicsLayer.h" -#include "TextureMapperImageBuffer.h" #include "Timer.h" #include <wtf/CurrentTime.h> -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - namespace WebCore { -struct BitmapTexturePoolEntry { - explicit BitmapTexturePoolEntry(PassRefPtr<BitmapTexture> texture) - : m_texture(texture) - { } - inline void markUsed() { m_timeLastUsed = monotonicallyIncreasingTime(); } - static bool compareTimeLastUsed(const BitmapTexturePoolEntry& a, const BitmapTexturePoolEntry& b) - { - return a.m_timeLastUsed - b.m_timeLastUsed > 0; - } - - RefPtr<BitmapTexture> m_texture; - double m_timeLastUsed; -}; - -class BitmapTexturePool { - WTF_MAKE_NONCOPYABLE(BitmapTexturePool); - WTF_MAKE_FAST_ALLOCATED; -public: - BitmapTexturePool(); - - PassRefPtr<BitmapTexture> acquireTexture(const IntSize&, TextureMapper*); - -private: - void scheduleReleaseUnusedTextures(); - void releaseUnusedTexturesTimerFired(Timer<BitmapTexturePool>*); - - Vector<BitmapTexturePoolEntry> m_textures; - Timer<BitmapTexturePool> m_releaseUnusedTexturesTimer; - - static const double s_releaseUnusedSecondsTolerance; - static const double s_releaseUnusedTexturesTimerInterval; -}; - -const double BitmapTexturePool::s_releaseUnusedSecondsTolerance = 3; -const double BitmapTexturePool::s_releaseUnusedTexturesTimerInterval = 0.5; - -BitmapTexturePool::BitmapTexturePool() - : m_releaseUnusedTexturesTimer(this, &BitmapTexturePool::releaseUnusedTexturesTimerFired) -{ } +TextureMapper::TextureMapper() = default; -void BitmapTexturePool::scheduleReleaseUnusedTextures() -{ - if (m_releaseUnusedTexturesTimer.isActive()) - m_releaseUnusedTexturesTimer.stop(); - - m_releaseUnusedTexturesTimer.startOneShot(s_releaseUnusedTexturesTimerInterval); -} - -void BitmapTexturePool::releaseUnusedTexturesTimerFired(Timer<BitmapTexturePool>*) -{ - if (m_textures.isEmpty()) - return; - - // Delete entries, which have been unused in s_releaseUnusedSecondsTolerance. - std::sort(m_textures.begin(), m_textures.end(), BitmapTexturePoolEntry::compareTimeLastUsed); - - double minUsedTime = monotonicallyIncreasingTime() - s_releaseUnusedSecondsTolerance; - for (size_t i = 0; i < m_textures.size(); ++i) { - if (m_textures[i].m_timeLastUsed < minUsedTime) { - m_textures.remove(i, m_textures.size() - i); - break; - } - } -} - -PassRefPtr<BitmapTexture> BitmapTexturePool::acquireTexture(const IntSize& size, TextureMapper* textureMapper) -{ - BitmapTexturePoolEntry* selectedEntry = 0; - for (size_t i = 0; i < m_textures.size(); ++i) { - BitmapTexturePoolEntry* entry = &m_textures[i]; - - // If the surface has only one reference (the one in m_textures), we can safely reuse it. - if (entry->m_texture->refCount() > 1) - continue; - - if (entry->m_texture->canReuseWith(size)) { - selectedEntry = entry; - break; - } - } - - if (!selectedEntry) { - m_textures.append(BitmapTexturePoolEntry(textureMapper->createTexture())); - selectedEntry = &m_textures.last(); - } - - scheduleReleaseUnusedTextures(); - selectedEntry->markUsed(); - return selectedEntry->m_texture; -} +TextureMapper::~TextureMapper() = default; PassRefPtr<BitmapTexture> TextureMapper::acquireTextureFromPool(const IntSize& size, const BitmapTexture::Flags flags) { - RefPtr<BitmapTexture> selectedTexture = m_texturePool->acquireTexture(size, this); + RefPtr<BitmapTexture> selectedTexture = m_texturePool->acquireTexture(size, flags); selectedTexture->reset(size, flags); - return selectedTexture; + return selectedTexture.release(); } -PassOwnPtr<TextureMapper> TextureMapper::create(AccelerationMode mode) +std::unique_ptr<TextureMapper> TextureMapper::create() { - if (mode == SoftwareMode) - return TextureMapperImageBuffer::create(); return platformCreateAccelerated(); } -TextureMapper::TextureMapper(AccelerationMode accelerationMode) - : m_context(0) - , m_interpolationQuality(InterpolationDefault) - , m_textDrawingMode(TextModeFill) - , m_texturePool(adoptPtr(new BitmapTexturePool())) - , m_accelerationMode(accelerationMode) - , m_isMaskMode(false) - , m_wrapMode(StretchWrap) -{ } - -TextureMapper::~TextureMapper() -{ } - -void BitmapTexture::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag) -{ - std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(targetRect.size()); - GraphicsContext* context = imageBuffer->context(); - context->setImageInterpolationQuality(textureMapper->imageInterpolationQuality()); - context->setTextDrawingMode(textureMapper->textDrawingMode()); - - IntRect sourceRect(targetRect); - sourceRect.setLocation(offset); - context->translate(-offset.x(), -offset.y()); - sourceLayer->paintGraphicsLayerContents(*context, sourceRect); - - RefPtr<Image> image = imageBuffer->copyImage(DontCopyBackingStore); - - updateContents(image.get(), targetRect, IntPoint(), updateContentsFlag); -} - } // namespace - -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h index 681b24ea1..7233d0dcc 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapper.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -20,13 +20,8 @@ #ifndef TextureMapper_h #define TextureMapper_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - -#if (PLATFORM(GTK) || PLATFORM(EFL)) && USE(OPENGL_ES_2) -#define TEXMAP_OPENGL_ES_2 -#endif - -#include "GraphicsContext.h" +#include "BitmapTexture.h" +#include "Color.h" #include "IntRect.h" #include "IntSize.h" #include "TransformationMatrix.h" @@ -43,68 +38,9 @@ class GraphicsLayer; class TextureMapper; class FilterOperations; -// A 2D texture that can be the target of software or GL rendering. -class BitmapTexture : public RefCounted<BitmapTexture> { -public: - enum Flag { - NoFlag = 0, - SupportsAlpha = 0x01 - }; - - enum UpdateContentsFlag { - UpdateCanModifyOriginalImageData, - UpdateCannotModifyOriginalImageData - }; - - typedef unsigned Flags; - - BitmapTexture() - : m_flags(0) - { - } - - virtual ~BitmapTexture() { } - virtual bool isBackedByOpenGL() const { return false; } - - virtual IntSize size() const = 0; - virtual void updateContents(Image*, const IntRect&, const IntPoint& offset, UpdateContentsFlag) = 0; - virtual void updateContents(TextureMapper*, GraphicsLayer*, const IntRect& target, const IntPoint& offset, UpdateContentsFlag); - virtual void updateContents(const void*, const IntRect& target, const IntPoint& offset, int bytesPerLine, UpdateContentsFlag) = 0; - virtual bool isValid() const = 0; - inline Flags flags() const { return m_flags; } - - virtual int bpp() const { return 32; } - virtual bool canReuseWith(const IntSize& /* contentsSize */, Flags = 0) { return false; } - void reset(const IntSize& size, Flags flags = 0) - { - m_flags = flags; - m_contentSize = size; - didReset(); - } - virtual void didReset() { } - - inline IntSize contentSize() const { return m_contentSize; } - inline int numberOfBytes() const { return size().width() * size().height() * bpp() >> 3; } - inline bool isOpaque() const { return !(m_flags & SupportsAlpha); } - -#if ENABLE(CSS_FILTERS) - virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const FilterOperations&) { return this; } -#endif - -protected: - IntSize m_contentSize; - -private: - Flags m_flags; -}; - -// A "context" class used to encapsulate accelerated texture mapping functions: i.e. drawing a texture -// onto the screen or into another texture with a specified transform, opacity and mask. class TextureMapper { WTF_MAKE_FAST_ALLOCATED; - friend class BitmapTexture; public: - enum AccelerationMode { SoftwareMode, OpenGLMode }; enum PaintFlag { PaintingMirrored = 1 << 0, }; @@ -116,7 +52,9 @@ public: typedef unsigned PaintFlags; - static PassOwnPtr<TextureMapper> create(AccelerationMode newMode = SoftwareMode); + static std::unique_ptr<TextureMapper> create(); + + explicit TextureMapper(); virtual ~TextureMapper(); enum ExposedEdges { @@ -136,20 +74,11 @@ public: // makes a surface the target for the following drawTexture calls. virtual void bindSurface(BitmapTexture* surface) = 0; - void setGraphicsContext(GraphicsContext* context) { m_context = context; } - GraphicsContext* graphicsContext() { return m_context; } virtual void beginClip(const TransformationMatrix&, const FloatRect&) = 0; virtual void endClip() = 0; virtual IntRect clipBounds() = 0; virtual PassRefPtr<BitmapTexture> createTexture() = 0; - void setImageInterpolationQuality(InterpolationQuality quality) { m_interpolationQuality = quality; } - void setTextDrawingMode(TextDrawingModeFlags mode) { m_textDrawingMode = mode; } - - InterpolationQuality imageInterpolationQuality() const { return m_interpolationQuality; } - TextDrawingModeFlags textDrawingMode() const { return m_textDrawingMode; } - AccelerationMode accelerationMode() const { return m_accelerationMode; } - virtual void beginPainting(PaintFlags = 0) { } virtual void endPainting() { } @@ -163,9 +92,7 @@ public: void setWrapMode(WrapMode m) { m_wrapMode = m; } protected: - explicit TextureMapper(AccelerationMode); - - GraphicsContext* m_context; + std::unique_ptr<BitmapTexturePool> m_texturePool; bool isInMaskMode() const { return m_isMaskMode; } WrapMode wrapMode() const { return m_wrapMode; } @@ -173,24 +100,18 @@ protected: private: #if USE(TEXTURE_MAPPER_GL) - static PassOwnPtr<TextureMapper> platformCreateAccelerated(); + static std::unique_ptr<TextureMapper> platformCreateAccelerated(); #else - static PassOwnPtr<TextureMapper> platformCreateAccelerated() + static std::unique_ptr<TextureMapper> platformCreateAccelerated() { - return PassOwnPtr<TextureMapper>(); + return nullptr; } #endif - InterpolationQuality m_interpolationQuality; - TextDrawingModeFlags m_textDrawingMode; - OwnPtr<BitmapTexturePool> m_texturePool; - AccelerationMode m_accelerationMode; - bool m_isMaskMode; + bool m_isMaskMode { false }; TransformationMatrix m_patternTransform; - WrapMode m_wrapMode; + WrapMode m_wrapMode { StretchWrap }; }; } #endif - -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp new file mode 100644 index 000000000..9cc1df6ad --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.cpp @@ -0,0 +1,393 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "TextureMapperAnimation.h" + +#include "LayoutSize.h" +#include "UnitBezier.h" +#include <wtf/CurrentTime.h> + +namespace WebCore { + +static RefPtr<FilterOperation> blendFunc(FilterOperation* fromOp, FilterOperation& toOp, double progress, const FloatSize& size, bool blendToPassthrough = false) +{ + if (toOp.blendingNeedsRendererSize()) + return toOp.blend(fromOp, progress, LayoutSize(size), blendToPassthrough); + return toOp.blend(fromOp, progress, blendToPassthrough); +} + +static FilterOperations applyFilterAnimation(const FilterOperations& from, const FilterOperations& to, double progress, const FloatSize& boxSize) +{ + // First frame of an animation. + if (!progress) + return from; + + // Last frame of an animation. + if (progress == 1) + return to; + + if (!from.isEmpty() && !to.isEmpty() && !from.operationsMatch(to)) + return to; + + FilterOperations result; + + size_t fromSize = from.operations().size(); + size_t toSize = to.operations().size(); + size_t size = std::max(fromSize, toSize); + for (size_t i = 0; i < size; i++) { + RefPtr<FilterOperation> fromOp = (i < fromSize) ? from.operations()[i].get() : nullptr; + RefPtr<FilterOperation> toOp = (i < toSize) ? to.operations()[i].get() : nullptr; + RefPtr<FilterOperation> blendedOp = toOp ? blendFunc(fromOp.get(), *toOp, progress, boxSize) : (fromOp ? blendFunc(nullptr, *fromOp, progress, boxSize, true) : nullptr); + if (blendedOp) + result.operations().append(blendedOp); + else { + RefPtr<FilterOperation> identityOp = PassthroughFilterOperation::create(); + if (progress > 0.5) + result.operations().append(toOp ? toOp : identityOp); + else + result.operations().append(fromOp ? fromOp : identityOp); + } + } + + return result; +} + +static bool shouldReverseAnimationValue(Animation::AnimationDirection direction, int loopCount) +{ + return (direction == Animation::AnimationDirectionAlternate && loopCount & 1) + || (direction == Animation::AnimationDirectionAlternateReverse && !(loopCount & 1)) + || direction == Animation::AnimationDirectionReverse; +} + +static double normalizedAnimationValue(double runningTime, double duration, Animation::AnimationDirection direction, double iterationCount) +{ + if (!duration) + return 0; + + const int loopCount = runningTime / duration; + const double lastFullLoop = duration * double(loopCount); + const double remainder = runningTime - lastFullLoop; + // Ignore remainder when we've reached the end of animation. + const double normalized = (loopCount == iterationCount) ? 1.0 : (remainder / duration); + + return shouldReverseAnimationValue(direction, loopCount) ? 1 - normalized : normalized; +} + +static double normalizedAnimationValueForFillsForwards(double iterationCount, Animation::AnimationDirection direction) +{ + if (direction == Animation::AnimationDirectionNormal) + return 1; + if (direction == Animation::AnimationDirectionReverse) + return 0; + return shouldReverseAnimationValue(direction, iterationCount) ? 1 : 0; +} + +static float applyOpacityAnimation(float fromOpacity, float toOpacity, double progress) +{ + // Optimization: special case the edge values (0 and 1). + if (progress == 1.0) + return toOpacity; + + if (!progress) + return fromOpacity; + + return fromOpacity + progress * (toOpacity - fromOpacity); +} + +static inline double solveEpsilon(double duration) +{ + return 1.0 / (200.0 * duration); +} + +static inline double solveCubicBezierFunction(double p1x, double p1y, double p2x, double p2y, double t, double duration) +{ + return UnitBezier(p1x, p1y, p2x, p2y).solve(t, solveEpsilon(duration)); +} + +static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t) +{ + if (stepAtStart) + return std::min(1.0, (floor(numSteps * t) + 1) / numSteps); + return floor(numSteps * t) / numSteps; +} + +static inline float applyTimingFunction(const TimingFunction& timingFunction, float progress, double duration) +{ + if (timingFunction.isCubicBezierTimingFunction()) { + auto& ctf = static_cast<const CubicBezierTimingFunction&>(timingFunction); + return solveCubicBezierFunction(ctf.x1(), ctf.y1(), ctf.x2(), ctf.y2(), progress, duration); + } + + if (timingFunction.isStepsTimingFunction()) { + auto& stf = static_cast<const StepsTimingFunction&>(timingFunction); + return solveStepsFunction(stf.numberOfSteps(), stf.stepAtStart(), double(progress)); + } + + return progress; +} + +static TransformationMatrix applyTransformAnimation(const TransformOperations& from, const TransformOperations& to, double progress, const FloatSize& boxSize, bool listsMatch) +{ + TransformationMatrix matrix; + + // First frame of an animation. + if (!progress) { + from.apply(boxSize, matrix); + return matrix; + } + + // Last frame of an animation. + if (progress == 1) { + to.apply(boxSize, matrix); + return matrix; + } + + // If we have incompatible operation lists, we blend the resulting matrices. + if (!listsMatch) { + TransformationMatrix fromMatrix; + to.apply(boxSize, matrix); + from.apply(boxSize, fromMatrix); + matrix.blend(fromMatrix, progress); + return matrix; + } + + // Animation to "-webkit-transform: none". + if (!to.size()) { + TransformOperations blended(from); + for (auto& operation : blended.operations()) + operation->blend(nullptr, progress, true)->apply(matrix, boxSize); + return matrix; + } + + // Animation from "-webkit-transform: none". + if (!from.size()) { + TransformOperations blended(to); + for (auto& operation : blended.operations()) + operation->blend(nullptr, 1 - progress, true)->apply(matrix, boxSize); + return matrix; + } + + // Normal animation with a matching operation list. + TransformOperations blended(to); + for (size_t i = 0; i < blended.operations().size(); ++i) + blended.operations()[i]->blend(from.at(i), progress, !from.at(i))->apply(matrix, boxSize); + return matrix; +} + +static const TimingFunction& timingFunctionForAnimationValue(const AnimationValue& animationValue, const Animation& animation) +{ + if (animationValue.timingFunction()) + return *animationValue.timingFunction(); + if (animation.timingFunction()) + return *animation.timingFunction(); + return CubicBezierTimingFunction::defaultTimingFunction(); +} + +TextureMapperAnimation::TextureMapperAnimation(const String& name, const KeyframeValueList& keyframes, const FloatSize& boxSize, const Animation& animation, bool listsMatch, double startTime, double pauseTime, AnimationState state) + : m_name(name.isSafeToSendToAnotherThread() ? name : name.isolatedCopy()) + , m_keyframes(keyframes) + , m_boxSize(boxSize) + , m_animation(Animation::create(animation)) + , m_listsMatch(listsMatch) + , m_startTime(startTime) + , m_pauseTime(pauseTime) + , m_totalRunningTime(0) + , m_lastRefreshedTime(m_startTime) + , m_state(state) +{ +} + +TextureMapperAnimation::TextureMapperAnimation(const TextureMapperAnimation& other) + : m_name(other.m_name.isSafeToSendToAnotherThread() ? other.m_name : other.m_name.isolatedCopy()) + , m_keyframes(other.m_keyframes) + , m_boxSize(other.m_boxSize) + , m_animation(Animation::create(*other.m_animation)) + , m_listsMatch(other.m_listsMatch) + , m_startTime(other.m_startTime) + , m_pauseTime(other.m_pauseTime) + , m_totalRunningTime(other.m_totalRunningTime) + , m_lastRefreshedTime(other.m_lastRefreshedTime) + , m_state(other.m_state) +{ +} + +void TextureMapperAnimation::apply(Client& client) +{ + if (!isActive()) + return; + + double totalRunningTime = computeTotalRunningTime(); + double normalizedValue = normalizedAnimationValue(totalRunningTime, m_animation->duration(), m_animation->direction(), m_animation->iterationCount()); + + if (m_animation->iterationCount() != Animation::IterationCountInfinite && totalRunningTime >= m_animation->duration() * m_animation->iterationCount()) { + m_state = AnimationState::Stopped; + m_pauseTime = 0; + if (m_animation->fillsForwards()) + normalizedValue = normalizedAnimationValueForFillsForwards(m_animation->iterationCount(), m_animation->direction()); + } + + if (!normalizedValue) { + applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), 0); + return; + } + + if (normalizedValue == 1.0) { + applyInternal(client, m_keyframes.at(m_keyframes.size() - 2), m_keyframes.at(m_keyframes.size() - 1), 1); + return; + } + if (m_keyframes.size() == 2) { + auto& timingFunction = timingFunctionForAnimationValue(m_keyframes.at(0), *m_animation); + normalizedValue = applyTimingFunction(timingFunction, normalizedValue, m_animation->duration()); + applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), normalizedValue); + return; + } + + for (size_t i = 0; i < m_keyframes.size() - 1; ++i) { + const AnimationValue& from = m_keyframes.at(i); + const AnimationValue& to = m_keyframes.at(i + 1); + if (from.keyTime() > normalizedValue || to.keyTime() < normalizedValue) + continue; + + normalizedValue = (normalizedValue - from.keyTime()) / (to.keyTime() - from.keyTime()); + auto& timingFunction = timingFunctionForAnimationValue(from, *m_animation); + normalizedValue = applyTimingFunction(timingFunction, normalizedValue, m_animation->duration()); + applyInternal(client, from, to, normalizedValue); + break; + } +} + +void TextureMapperAnimation::pause(double time) +{ + m_state = AnimationState::Paused; + m_pauseTime = time; +} + +void TextureMapperAnimation::resume() +{ + m_state = AnimationState::Playing; + m_pauseTime = 0; + m_totalRunningTime = m_pauseTime; + m_lastRefreshedTime = monotonicallyIncreasingTime(); +} + +double TextureMapperAnimation::computeTotalRunningTime() +{ + if (m_state == AnimationState::Paused) + return m_pauseTime; + + double oldLastRefreshedTime = m_lastRefreshedTime; + m_lastRefreshedTime = monotonicallyIncreasingTime(); + m_totalRunningTime += m_lastRefreshedTime - oldLastRefreshedTime; + return m_totalRunningTime; +} + +bool TextureMapperAnimation::isActive() const +{ + return m_state != AnimationState::Stopped || m_animation->fillsForwards(); +} + +void TextureMapperAnimation::applyInternal(Client& client, const AnimationValue& from, const AnimationValue& to, float progress) +{ + switch (m_keyframes.property()) { + case AnimatedPropertyOpacity: + client.setAnimatedOpacity(applyOpacityAnimation((static_cast<const FloatAnimationValue&>(from).value()), (static_cast<const FloatAnimationValue&>(to).value()), progress)); + return; + case AnimatedPropertyTransform: + client.setAnimatedTransform(applyTransformAnimation(static_cast<const TransformAnimationValue&>(from).value(), static_cast<const TransformAnimationValue&>(to).value(), progress, m_boxSize, m_listsMatch)); + return; + case AnimatedPropertyFilter: + client.setAnimatedFilters(applyFilterAnimation(static_cast<const FilterAnimationValue&>(from).value(), static_cast<const FilterAnimationValue&>(to).value(), progress, m_boxSize)); + return; + default: + ASSERT_NOT_REACHED(); + } +} + +void TextureMapperAnimations::add(const TextureMapperAnimation& animation) +{ + // Remove the old state if we are resuming a paused animation. + remove(animation.name(), animation.keyframes().property()); + + m_animations.append(animation); +} + +void TextureMapperAnimations::remove(const String& name) +{ + m_animations.removeAllMatching([&name] (const TextureMapperAnimation& animation) { + return animation.name() == name; + }); +} + +void TextureMapperAnimations::remove(const String& name, AnimatedPropertyID property) +{ + m_animations.removeAllMatching([&name, property] (const TextureMapperAnimation& animation) { + return animation.name() == name && animation.keyframes().property() == property; + }); +} + +void TextureMapperAnimations::pause(const String& name, double offset) +{ + for (auto& animation : m_animations) { + if (animation.name() == name) + animation.pause(offset); + } +} + +void TextureMapperAnimations::suspend(double offset) +{ + for (auto& animation : m_animations) + animation.pause(offset); +} + +void TextureMapperAnimations::resume() +{ + for (auto& animation : m_animations) + animation.resume(); +} + +void TextureMapperAnimations::apply(TextureMapperAnimation::Client& client) +{ + for (auto& animation : m_animations) + animation.apply(client); +} + +bool TextureMapperAnimations::hasActiveAnimationsOfType(AnimatedPropertyID type) const +{ + return std::any_of(m_animations.begin(), m_animations.end(), + [&type](const TextureMapperAnimation& animation) { return animation.isActive() && animation.keyframes().property() == type; }); +} + +bool TextureMapperAnimations::hasRunningAnimations() const +{ + return std::any_of(m_animations.begin(), m_animations.end(), + [](const TextureMapperAnimation& animation) { return animation.state() == TextureMapperAnimation::AnimationState::Playing; }); +} + +TextureMapperAnimations TextureMapperAnimations::getActiveAnimations() const +{ + TextureMapperAnimations active; + for (auto& animation : m_animations) { + if (animation.isActive()) + active.add(animation); + } + return active; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.h b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.h new file mode 100644 index 000000000..6a447d76e --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperAnimation.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TextureMapperAnimation_h +#define TextureMapperAnimation_h + +#include "GraphicsLayer.h" + +namespace WebCore { + +class TransformationMatrix; + +class TextureMapperAnimation { +public: + enum class AnimationState { Playing, Paused, Stopped }; + + class Client { + public: + virtual void setAnimatedTransform(const TransformationMatrix&) = 0; + virtual void setAnimatedOpacity(float) = 0; + virtual void setAnimatedFilters(const FilterOperations&) = 0; + }; + + TextureMapperAnimation() + : m_keyframes(AnimatedPropertyInvalid) + { } + TextureMapperAnimation(const String&, const KeyframeValueList&, const FloatSize&, const Animation&, bool, double, double, AnimationState); + TextureMapperAnimation(const TextureMapperAnimation&); + + void apply(Client&); + void pause(double); + void resume(); + bool isActive() const; + + const String& name() const { return m_name; } + const KeyframeValueList& keyframes() const { return m_keyframes; } + const FloatSize& boxSize() const { return m_boxSize; } + const RefPtr<Animation> animation() const { return m_animation; } + bool listsMatch() const { return m_listsMatch; } + double startTime() const { return m_startTime; } + double pauseTime() const { return m_pauseTime; } + AnimationState state() const { return m_state; } + +private: + void applyInternal(Client&, const AnimationValue& from, const AnimationValue& to, float progress); + double computeTotalRunningTime(); + + String m_name; + KeyframeValueList m_keyframes; + FloatSize m_boxSize; + RefPtr<Animation> m_animation; + bool m_listsMatch; + double m_startTime; + double m_pauseTime; + double m_totalRunningTime; + double m_lastRefreshedTime; + AnimationState m_state; +}; + +class TextureMapperAnimations { +public: + TextureMapperAnimations() = default; + + void add(const TextureMapperAnimation&); + void remove(const String& name); + void remove(const String& name, AnimatedPropertyID); + void pause(const String&, double); + void suspend(double); + void resume(); + + void apply(TextureMapperAnimation::Client&); + + bool isEmpty() const { return m_animations.isEmpty(); } + size_t size() const { return m_animations.size(); } + const Vector<TextureMapperAnimation>& animations() const { return m_animations; } + Vector<TextureMapperAnimation>& animations() { return m_animations; } + + bool hasRunningAnimations() const; + bool hasActiveAnimationsOfType(AnimatedPropertyID type) const; + TextureMapperAnimations getActiveAnimations() const; + +private: + Vector<TextureMapperAnimation> m_animations; +}; + +} + +#endif // TextureMapperAnimation_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp index e68bc0914..ebed19a89 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.cpp @@ -19,18 +19,12 @@ #include "config.h" -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "TextureMapperBackingStore.h" #include "GraphicsLayer.h" #include "ImageBuffer.h" #include "TextureMapper.h" -#if USE(GRAPHICS_SURFACE) -#include "GraphicsSurface.h" -#include "TextureMapperGL.h" -#endif - namespace WebCore { unsigned TextureMapperBackingStore::calculateExposedTileEdges(const FloatRect& totalRect, const FloatRect& tileRect) @@ -48,4 +42,3 @@ unsigned TextureMapperBackingStore::calculateExposedTileEdges(const FloatRect& t } } -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h index 4bae45b4f..914604171 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperBackingStore.h @@ -20,27 +20,21 @@ #ifndef TextureMapperBackingStore_h #define TextureMapperBackingStore_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - #include "FloatRect.h" #include "Image.h" #include "TextureMapper.h" #include "TextureMapperPlatformLayer.h" #include <wtf/RefPtr.h> -#if USE(GRAPHICS_SURFACE) -#include "GraphicsSurface.h" -#endif - namespace WebCore { class GraphicsLayer; class TextureMapperBackingStore : public TextureMapperPlatformLayer, public RefCounted<TextureMapperBackingStore> { public: - virtual PassRefPtr<BitmapTexture> texture() const = 0; - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float) = 0; - virtual void drawRepaintCounter(TextureMapper*, int /* repaintCount */, const Color&, const FloatRect&, const TransformationMatrix&) { } + virtual RefPtr<BitmapTexture> texture() const = 0; + void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix&, float) override = 0; + virtual void drawRepaintCounter(TextureMapper&, int /* repaintCount */, const Color&, const FloatRect&, const TransformationMatrix&) { } virtual ~TextureMapperBackingStore() { } protected: @@ -48,6 +42,5 @@ protected: }; } -#endif #endif // TextureMapperBackingStore_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp index d74477010..db6a7a0d3 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.cpp @@ -21,8 +21,6 @@ #include "config.h" -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - #include "TextureMapperFPSCounter.h" #include "TextureMapper.h" @@ -46,7 +44,7 @@ TextureMapperFPSCounter::TextureMapperFPSCounter() } } -void TextureMapperFPSCounter::updateFPSAndDisplay(TextureMapper* textureMapper, const FloatPoint& location, const TransformationMatrix& matrix) +void TextureMapperFPSCounter::updateFPSAndDisplay(TextureMapper& textureMapper, const FloatPoint& location, const TransformationMatrix& matrix) { if (!m_isShowingFPS) return; @@ -59,9 +57,7 @@ void TextureMapperFPSCounter::updateFPSAndDisplay(TextureMapper* textureMapper, m_fpsTimestamp += delta; } - textureMapper->drawNumber(m_lastFPS, Color::black, location, matrix); + textureMapper.drawNumber(m_lastFPS, Color::black, location, matrix); } } // namespace WebCore - -#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h index 006237383..8aa4a9425 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperFPSCounter.h @@ -22,7 +22,6 @@ #ifndef TextureMapperFPSCounter_h #define TextureMapperFPSCounter_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "FloatPoint.h" #include "TransformationMatrix.h" #include <wtf/Noncopyable.h> @@ -35,7 +34,7 @@ class TextureMapperFPSCounter { WTF_MAKE_FAST_ALLOCATED; public: TextureMapperFPSCounter(); - void updateFPSAndDisplay(TextureMapper*, const FloatPoint& = FloatPoint::zero(), const TransformationMatrix& = TransformationMatrix()); + void updateFPSAndDisplay(TextureMapper&, const FloatPoint& = FloatPoint::zero(), const TransformationMatrix& = TransformationMatrix()); private: bool m_isShowingFPS; @@ -47,8 +46,4 @@ private: } // namespace WebCore -#endif // USE(ACCELERATED_COMPOSITING) - #endif // TextureMapperFPSCounter_h - - diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGC3DPlatformLayer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperGC3DPlatformLayer.cpp new file mode 100644 index 000000000..9a9f4fb06 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGC3DPlatformLayer.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2011, 2012, 2017 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "TextureMapperGC3DPlatformLayer.h" + +#if ENABLE(GRAPHICS_CONTEXT_3D) && USE(TEXTURE_MAPPER) + +#if USE(OPENGL_ES_2) +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#endif + +#include "BitmapTextureGL.h" +#include "GLContext.h" +#include "TextureMapperPlatformLayerBuffer.h" + +namespace WebCore { + +TextureMapperGC3DPlatformLayer::TextureMapperGC3DPlatformLayer(GraphicsContext3D& context, GraphicsContext3D::RenderStyle renderStyle) + : m_context(context) + , m_renderStyle(renderStyle) +{ + switch (renderStyle) { + case GraphicsContext3D::RenderOffscreen: + m_glContext = GLContext::createOffscreenContext(&PlatformDisplay::sharedDisplayForCompositing()); + break; + case GraphicsContext3D::RenderToCurrentGLContext: + break; + case GraphicsContext3D::RenderDirectlyToHostWindow: + ASSERT_NOT_REACHED(); + break; + } + +#if USE(COORDINATED_GRAPHICS_THREADED) + if (m_renderStyle == GraphicsContext3D::RenderOffscreen) + m_platformLayerProxy = adoptRef(new TextureMapperPlatformLayerProxy()); +#endif +} + +TextureMapperGC3DPlatformLayer::~TextureMapperGC3DPlatformLayer() +{ +#if !USE(COORDINATED_GRAPHICS_THREADED) + if (client()) + client()->platformLayerWillBeDestroyed(); +#endif +} + +bool TextureMapperGC3DPlatformLayer::makeContextCurrent() +{ + return m_glContext ? m_glContext->makeContextCurrent() : false; +} + +PlatformGraphicsContext3D TextureMapperGC3DPlatformLayer::platformContext() +{ + return m_glContext ? m_glContext->platformContext() : GLContext::current()->platformContext(); +} + +#if USE(COORDINATED_GRAPHICS_THREADED) +RefPtr<TextureMapperPlatformLayerProxy> TextureMapperGC3DPlatformLayer::proxy() const +{ + return m_platformLayerProxy.copyRef(); +} + +void TextureMapperGC3DPlatformLayer::swapBuffersIfNeeded() +{ + ASSERT(m_renderStyle == GraphicsContext3D::RenderOffscreen); + if (m_context.layerComposited()) + return; + + m_context.prepareTexture(); + IntSize textureSize(m_context.m_currentWidth, m_context.m_currentHeight); + TextureMapperGL::Flags flags = TextureMapperGL::ShouldFlipTexture | (m_context.m_attrs.alpha ? TextureMapperGL::ShouldBlend : 0); + + { + LockHolder holder(m_platformLayerProxy->lock()); + m_platformLayerProxy->pushNextBuffer(std::make_unique<TextureMapperPlatformLayerBuffer>(m_context.m_compositorTexture, textureSize, flags)); + } + + m_context.markLayerComposited(); +} +#else +void TextureMapperGC3DPlatformLayer::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) +{ + if (!m_glContext) + return; + + ASSERT(m_renderStyle == GraphicsContext3D::RenderOffscreen); + + m_context.markLayerComposited(); + +#if USE(TEXTURE_MAPPER_GL) + if (m_context.m_attrs.antialias && m_context.m_state.boundFBO == m_context.m_multisampleFBO) { + GLContext* previousActiveContext = GLContext::current(); + if (previousActiveContext != m_glContext.get()) + m_context.makeContextCurrent(); + + m_context.resolveMultisamplingIfNecessary(); + ::glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_context.m_state.boundFBO); + + if (previousActiveContext && previousActiveContext != m_glContext.get()) + previousActiveContext->makeContextCurrent(); + } + + TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper); + TextureMapperGL::Flags flags = TextureMapperGL::ShouldFlipTexture | (m_context.m_attrs.alpha ? TextureMapperGL::ShouldBlend : 0); + IntSize textureSize(m_context.m_currentWidth, m_context.m_currentHeight); + texmapGL.drawTexture(m_context.m_texture, flags, textureSize, targetRect, matrix, opacity); +#endif // USE(TEXTURE_MAPPER_GL) +} +#endif // USE(COORDINATED_GRAPHICS_THREADED) + +} // namespace WebCore + +#endif // ENABLE(GRAPHICS_CONTEXT_3D) && USE(TEXTURE_MAPPER) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGC3DPlatformLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperGC3DPlatformLayer.h new file mode 100644 index 000000000..dd3f74fce --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGC3DPlatformLayer.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011, 2012, 2017 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#pragma once + +#if ENABLE(GRAPHICS_CONTEXT_3D) && USE(TEXTURE_MAPPER) + +#include "GraphicsContext3D.h" +#include "PlatformLayer.h" +#include "TextureMapperPlatformLayer.h" +#include "TextureMapperPlatformLayerProxy.h" + +namespace WebCore { + +class BitmapTextureGL; +class GLContext; +class TextureMapperPlatformLayerProxy; + +class TextureMapperGC3DPlatformLayer : public PlatformLayer { +public: + TextureMapperGC3DPlatformLayer(GraphicsContext3D&, GraphicsContext3D::RenderStyle); + virtual ~TextureMapperGC3DPlatformLayer(); + + bool makeContextCurrent(); + PlatformGraphicsContext3D platformContext(); + GraphicsContext3D::RenderStyle renderStyle() { return m_renderStyle; } + +#if USE(COORDINATED_GRAPHICS_THREADED) + RefPtr<TextureMapperPlatformLayerProxy> proxy() const override; + void swapBuffersIfNeeded() override; +#else + virtual void paintToTextureMapper(TextureMapper&, const FloatRect& target, const TransformationMatrix&, float opacity); +#endif + +private: + GraphicsContext3D& m_context; + std::unique_ptr<GLContext> m_glContext; + GraphicsContext3D::RenderStyle m_renderStyle; + +#if USE(COORDINATED_GRAPHICS_THREADED) + RefPtr<TextureMapperPlatformLayerProxy> m_platformLayerProxy; + RefPtr<BitmapTextureGL> m_compositorTexture; +#endif +}; + +} // namespace WebCore + +#endif // ENABLE(GRAPHICS_CONTEXT_3D) && USE(TEXTURE_MAPPER) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp index 05b884bd5..7464d047e 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.cpp @@ -22,6 +22,10 @@ #include "config.h" #include "TextureMapperGL.h" +#if USE(TEXTURE_MAPPER_GL) + +#include "BitmapTextureGL.h" +#include "BitmapTexturePool.h" #include "Extensions3D.h" #include "FilterOperations.h" #include "GraphicsContext.h" @@ -31,9 +35,10 @@ #include "TextureMapperShaderProgram.h" #include "Timer.h" #include <wtf/HashMap.h> +#include <wtf/NeverDestroyed.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> -#include <wtf/TemporaryChange.h> +#include <wtf/SetForScope.h> #if USE(CAIRO) #include "CairoUtilities.h" @@ -42,191 +47,84 @@ #include <wtf/text/CString.h> #endif -#if !USE(TEXMAP_OPENGL_ES_2) -// FIXME: Move to Extensions3D.h. -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#endif - -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - namespace WebCore { -struct TextureMapperGLData { + +class TextureMapperGLData { WTF_MAKE_FAST_ALLOCATED; public: - struct SharedGLData : public RefCounted<SharedGLData> { + explicit TextureMapperGLData(GraphicsContext3D&); + ~TextureMapperGLData(); - typedef HashMap<PlatformGraphicsContext3D, SharedGLData*> GLContextDataMap; - static GLContextDataMap& glContextDataMap() - { - static GLContextDataMap map; - return map; - } + void initializeStencil(); + Platform3DObject getStaticVBO(GC3Denum target, GC3Dsizeiptr, const void* data); + Ref<TextureMapperShaderProgram> getShaderProgram(TextureMapperShaderProgram::Options); + + TransformationMatrix projectionMatrix; + TextureMapper::PaintFlags PaintFlags { 0 }; + GC3Dint previousProgram { 0 }; + GC3Dint targetFrameBuffer { 0 }; + bool didModifyStencil { false }; + GC3Dint previousScissorState { 0 }; + GC3Dint previousDepthState { 0 }; + GC3Dint viewport[4] { 0, }; + GC3Dint previousScissor[4] { 0, }; + RefPtr<BitmapTexture> currentSurface; + const BitmapTextureGL::FilterInfo* filterInfo { nullptr }; - static PassRefPtr<SharedGLData> currentSharedGLData(GraphicsContext3D* context) +private: + class SharedGLData : public RefCounted<SharedGLData> { + public: + static Ref<SharedGLData> currentSharedGLData(GraphicsContext3D& context) { - GLContextDataMap::iterator it = glContextDataMap().find(context->platformGraphicsContext3D()); - if (it != glContextDataMap().end()) - return it->value; + auto it = contextDataMap().find(context.platformGraphicsContext3D()); + if (it != contextDataMap().end()) + return *it->value; - return adoptRef(new SharedGLData(context)); + Ref<SharedGLData> data = adoptRef(*new SharedGLData(context)); + contextDataMap().add(context.platformGraphicsContext3D(), data.ptr()); + return data; } - PassRefPtr<TextureMapperShaderProgram> getShaderProgram(TextureMapperShaderProgram::Options options) + ~SharedGLData() { - HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram> >::AddResult result = m_programs.add(options, nullptr); - if (result.isNewEntry) - result.iterator->value = TextureMapperShaderProgram::create(m_context, options); - - return result.iterator->value; + ASSERT(std::any_of(contextDataMap().begin(), contextDataMap().end(), + [this](auto& entry) { return entry.value == this; })); + contextDataMap().removeIf([this](auto& entry) { return entry.value == this; }); } - HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram> > m_programs; - RefPtr<GraphicsContext3D> m_context; + private: + friend class TextureMapperGLData; - explicit SharedGLData(GraphicsContext3D* context) - : m_context(context) + using GLContextDataMap = HashMap<PlatformGraphicsContext3D, SharedGLData*>; + static GLContextDataMap& contextDataMap() { - glContextDataMap().add(context->platformGraphicsContext3D(), this); + static NeverDestroyed<GLContextDataMap> map; + return map; } - ~SharedGLData() + explicit SharedGLData(GraphicsContext3D& context) { - GLContextDataMap::const_iterator end = glContextDataMap().end(); - GLContextDataMap::iterator it; - for (it = glContextDataMap().begin(); it != end; ++it) { - if (it->value == this) - break; - } - - ASSERT(it != end); - glContextDataMap().remove(it); + contextDataMap().add(context.platformGraphicsContext3D(), this); } - }; - - SharedGLData& sharedGLData() const - { - return *sharedData; - } - void initializeStencil(); - - explicit TextureMapperGLData(GraphicsContext3D* context) - : context(context) - , PaintFlags(0) - , previousProgram(0) - , targetFrameBuffer(0) - , didModifyStencil(false) - , previousScissorState(0) - , previousDepthState(0) - , sharedData(TextureMapperGLData::SharedGLData::currentSharedGLData(this->context)) -#if ENABLE(CSS_FILTERS) - , filterInfo(0) -#endif - { } - - ~TextureMapperGLData(); - Platform3DObject getStaticVBO(GC3Denum target, GC3Dsizeiptr, const void* data); + HashMap<TextureMapperShaderProgram::Options, RefPtr<TextureMapperShaderProgram>> m_programs; + }; - GraphicsContext3D* context; - TransformationMatrix projectionMatrix; - TextureMapper::PaintFlags PaintFlags; - GC3Dint previousProgram; - GC3Dint targetFrameBuffer; - bool didModifyStencil; - GC3Dint previousScissorState; - GC3Dint previousDepthState; - GC3Dint viewport[4]; - GC3Dint previousScissor[4]; - RefPtr<SharedGLData> sharedData; - RefPtr<BitmapTexture> currentSurface; - HashMap<const void*, Platform3DObject> vbos; -#if ENABLE(CSS_FILTERS) - const BitmapTextureGL::FilterInfo* filterInfo; -#endif + GraphicsContext3D& m_context; + Ref<SharedGLData> m_sharedGLData; + HashMap<const void*, Platform3DObject> m_vbos; }; -Platform3DObject TextureMapperGLData::getStaticVBO(GC3Denum target, GC3Dsizeiptr size, const void* data) +TextureMapperGLData::TextureMapperGLData(GraphicsContext3D& context) + : m_context(context) + , m_sharedGLData(SharedGLData::currentSharedGLData(m_context)) { - HashMap<const void*, Platform3DObject>::AddResult result = vbos.add(data, 0); - if (result.isNewEntry) { - Platform3DObject vbo = context->createBuffer(); - context->bindBuffer(target, vbo); - context->bufferData(target, size, data, GraphicsContext3D::STATIC_DRAW); - result.iterator->value = vbo; - } - - return result.iterator->value; } TextureMapperGLData::~TextureMapperGLData() { - HashMap<const void*, Platform3DObject>::iterator end = vbos.end(); - for (HashMap<const void*, Platform3DObject>::iterator it = vbos.begin(); it != end; ++it) - context->deleteBuffer(it->value); -} - -void TextureMapperGL::ClipStack::reset(const IntRect& rect, TextureMapperGL::ClipStack::YAxisMode mode) -{ - clipStack.clear(); - size = rect.size(); - yAxisMode = mode; - clipState = TextureMapperGL::ClipState(rect); - clipStateDirty = true; -} - -void TextureMapperGL::ClipStack::intersect(const IntRect& rect) -{ - clipState.scissorBox.intersect(rect); - clipStateDirty = true; -} - -void TextureMapperGL::ClipStack::setStencilIndex(int stencilIndex) -{ - clipState.stencilIndex = stencilIndex; - clipStateDirty = true; -} - -void TextureMapperGL::ClipStack::push() -{ - clipStack.append(clipState); - clipStateDirty = true; -} - -void TextureMapperGL::ClipStack::pop() -{ - if (clipStack.isEmpty()) - return; - clipState = clipStack.last(); - clipStack.removeLast(); - clipStateDirty = true; -} - -void TextureMapperGL::ClipStack::apply(GraphicsContext3D* context) -{ - if (clipState.scissorBox.isEmpty()) - return; - - context->scissor(clipState.scissorBox.x(), - (yAxisMode == InvertedYAxis) ? size.height() - clipState.scissorBox.maxY() : clipState.scissorBox.y(), - clipState.scissorBox.width(), clipState.scissorBox.height()); - context->stencilOp(GraphicsContext3D::KEEP, GraphicsContext3D::KEEP, GraphicsContext3D::KEEP); - context->stencilFunc(GraphicsContext3D::EQUAL, clipState.stencilIndex - 1, clipState.stencilIndex - 1); - if (clipState.stencilIndex == 1) - context->disable(GraphicsContext3D::STENCIL_TEST); - else - context->enable(GraphicsContext3D::STENCIL_TEST); -} - -void TextureMapperGL::ClipStack::applyIfNeeded(GraphicsContext3D* context) -{ - if (!clipStateDirty) - return; - - clipStateDirty = false; - apply(context); + for (auto& entry : m_vbos) + m_context.deleteBuffer(entry.value); } void TextureMapperGLData::initializeStencil() @@ -239,30 +137,45 @@ void TextureMapperGLData::initializeStencil() if (didModifyStencil) return; - context->clearStencil(0); - context->clear(GraphicsContext3D::STENCIL_BUFFER_BIT); + m_context.clearStencil(0); + m_context.clear(GraphicsContext3D::STENCIL_BUFFER_BIT); didModifyStencil = true; } -BitmapTextureGL* toBitmapTextureGL(BitmapTexture* texture) +Platform3DObject TextureMapperGLData::getStaticVBO(GC3Denum target, GC3Dsizeiptr size, const void* data) { - if (!texture || !texture->isBackedByOpenGL()) - return 0; + auto addResult = m_vbos.ensure(data, + [this, target, size, data] { + Platform3DObject vbo = m_context.createBuffer(); + m_context.bindBuffer(target, vbo); + m_context.bufferData(target, size, data, GraphicsContext3D::STATIC_DRAW); + return vbo; + }); + return addResult.iterator->value; +} - return static_cast<BitmapTextureGL*>(texture); +Ref<TextureMapperShaderProgram> TextureMapperGLData::getShaderProgram(TextureMapperShaderProgram::Options options) +{ + auto addResult = m_sharedGLData->m_programs.ensure(options, + [this, options] { return TextureMapperShaderProgram::create(Ref<GraphicsContext3D>(m_context), options); }); + return *addResult.iterator->value; } TextureMapperGL::TextureMapperGL() - : TextureMapper(OpenGLMode) - , m_enableEdgeDistanceAntialiasing(false) + : m_enableEdgeDistanceAntialiasing(false) { m_context3D = GraphicsContext3D::createForCurrentGLContext(); - m_data = new TextureMapperGLData(m_context3D.get()); + ASSERT(m_context3D); + + m_data = new TextureMapperGLData(*m_context3D); +#if USE(TEXTURE_MAPPER_GL) + m_texturePool = std::make_unique<BitmapTexturePool>(m_context3D.copyRef()); +#endif } -TextureMapperGL::ClipStack& TextureMapperGL::clipStack() +ClipStack& TextureMapperGL::clipStack() { - return data().currentSurface ? toBitmapTextureGL(data().currentSurface.get())->m_clipStack : m_clipStack; + return data().currentSurface ? toBitmapTextureGL(data().currentSurface.get())->clipStack() : m_clipStack; } void TextureMapperGL::beginPainting(PaintFlags flags) @@ -276,7 +189,7 @@ void TextureMapperGL::beginPainting(PaintFlags flags) m_context3D->depthMask(0); m_context3D->getIntegerv(GraphicsContext3D::VIEWPORT, data().viewport); m_context3D->getIntegerv(GraphicsContext3D::SCISSOR_BOX, data().previousScissor); - m_clipStack.reset(IntRect(0, 0, data().viewport[2], data().viewport[3]), ClipStack::InvertedYAxis); + m_clipStack.reset(IntRect(0, 0, data().viewport[2], data().viewport[3]), flags & PaintingMirrored ? ClipStack::YAxisMode::Default : ClipStack::YAxisMode::Inverted); m_context3D->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &data().targetFrameBuffer); data().PaintFlags = flags; bindSurface(0); @@ -308,7 +221,7 @@ void TextureMapperGL::drawBorder(const Color& color, float width, const FloatRec if (clipStack().isCurrentScissorBoxEmpty()) return; - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(TextureMapperShaderProgram::SolidColor); + Ref<TextureMapperShaderProgram> program = data().getShaderProgram(TextureMapperShaderProgram::SolidColor); m_context3D->useProgram(program->programID()); float r, g, b, a; @@ -316,7 +229,7 @@ void TextureMapperGL::drawBorder(const Color& color, float width, const FloatRec m_context3D->uniform4f(program->colorLocation(), r, g, b, a); m_context3D->lineWidth(width); - draw(targetRect, modelViewMatrix, program.get(), GraphicsContext3D::LINE_LOOP, color.hasAlpha() ? ShouldBlend : 0); + draw(targetRect, modelViewMatrix, program.get(), GraphicsContext3D::LINE_LOOP, !color.isOpaque() ? ShouldBlend : 0); } // FIXME: drawNumber() should save a number texture-atlas and re-use whenever possible. @@ -333,9 +246,15 @@ void TextureMapperGL::drawNumber(int number, const Color& color, const FloatPoin cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t* cr = cairo_create(surface); - float r, g, b, a; - color.getRGBA(r, g, b, a); - cairo_set_source_rgba(cr, b, g, r, a); // Since we won't swap R+B when uploading a texture, paint with the swapped R+B color. + // Since we won't swap R+B when uploading a texture, paint with the swapped R+B color. + if (color.isExtended()) + cairo_set_source_rgba(cr, color.asExtended().blue(), color.asExtended().green(), color.asExtended().red(), color.asExtended().alpha()); + else { + float r, g, b, a; + color.getRGBA(r, g, b, a); + cairo_set_source_rgba(cr, b, g, r, a); + } + cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); @@ -367,8 +286,6 @@ void TextureMapperGL::drawNumber(int number, const Color& color, const FloatPoin #endif } -#if ENABLE(CSS_FILTERS) - static TextureMapperShaderProgram::Options optionsForFilterType(FilterOperation::OperationType type, unsigned pass) { switch (type) { @@ -399,27 +316,6 @@ static TextureMapperShaderProgram::Options optionsForFilterType(FilterOperation: } } -static unsigned getPassesRequiredForFilter(FilterOperation::OperationType type) -{ - switch (type) { - case FilterOperation::GRAYSCALE: - case FilterOperation::SEPIA: - case FilterOperation::SATURATE: - case FilterOperation::HUE_ROTATE: - case FilterOperation::INVERT: - case FilterOperation::BRIGHTNESS: - case FilterOperation::CONTRAST: - case FilterOperation::OPACITY: - return 1; - case FilterOperation::BLUR: - case FilterOperation::DROP_SHADOW: - // We use two-passes (vertical+horizontal) for blur and drop-shadow. - return 2; - default: - return 0; - } -} - // Create a normal distribution of 21 values between -2 and 2. static const unsigned GaussianKernelHalfWidth = 11; static const float GaussianKernelStep = 0.2; @@ -453,23 +349,23 @@ static float* gaussianKernel() return kernel; } -static void prepareFilterProgram(TextureMapperShaderProgram* program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture) +static void prepareFilterProgram(TextureMapperShaderProgram& program, const FilterOperation& operation, unsigned pass, const IntSize& size, GC3Duint contentTexture) { - RefPtr<GraphicsContext3D> context = program->context(); - context->useProgram(program->programID()); + Ref<GraphicsContext3D> context = program.context(); + context->useProgram(program.programID()); switch (operation.type()) { case FilterOperation::GRAYSCALE: case FilterOperation::SEPIA: case FilterOperation::SATURATE: case FilterOperation::HUE_ROTATE: - context->uniform1f(program->filterAmountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()); + context->uniform1f(program.filterAmountLocation(), static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()); break; case FilterOperation::INVERT: case FilterOperation::BRIGHTNESS: case FilterOperation::CONTRAST: case FilterOperation::OPACITY: - context->uniform1f(program->filterAmountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()); + context->uniform1f(program.filterAmountLocation(), static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()); break; case FilterOperation::BLUR: { const BlurFilterOperation& blur = static_cast<const BlurFilterOperation&>(operation); @@ -481,29 +377,29 @@ static void prepareFilterProgram(TextureMapperShaderProgram* program, const Filt else radius.setWidth(floatValueForLength(blur.stdDeviation(), size.width()) / size.width()); - context->uniform2f(program->blurRadiusLocation(), radius.width(), radius.height()); - context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); + context->uniform2f(program.blurRadiusLocation(), radius.width(), radius.height()); + context->uniform1fv(program.gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); break; } case FilterOperation::DROP_SHADOW: { const DropShadowFilterOperation& shadow = static_cast<const DropShadowFilterOperation&>(operation); - context->uniform1fv(program->gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); + context->uniform1fv(program.gaussianKernelLocation(), GaussianKernelHalfWidth, gaussianKernel()); switch (pass) { case 0: // First pass: horizontal alpha blur. - context->uniform2f(program->blurRadiusLocation(), shadow.stdDeviation() / float(size.width()), 0); - context->uniform2f(program->shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height())); + context->uniform2f(program.blurRadiusLocation(), shadow.stdDeviation() / float(size.width()), 0); + context->uniform2f(program.shadowOffsetLocation(), float(shadow.location().x()) / float(size.width()), float(shadow.location().y()) / float(size.height())); break; case 1: // Second pass: we need the shadow color and the content texture for compositing. float r, g, b, a; Color(premultipliedARGBFromColor(shadow.color())).getRGBA(r, g, b, a); - context->uniform4f(program->colorLocation(), r, g, b, a); - context->uniform2f(program->blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height())); - context->uniform2f(program->shadowOffsetLocation(), 0, 0); + context->uniform4f(program.colorLocation(), r, g, b, a); + context->uniform2f(program.blurRadiusLocation(), 0, shadow.stdDeviation() / float(size.height())); + context->uniform2f(program.shadowOffsetLocation(), 0, 0); context->activeTexture(GraphicsContext3D::TEXTURE1); context->bindTexture(GraphicsContext3D::TEXTURE_2D, contentTexture); - context->uniform1i(program->contentTextureLocation(), 1); + context->uniform1i(program.contentTextureLocation(), 1); break; } break; @@ -512,7 +408,6 @@ static void prepareFilterProgram(TextureMapperShaderProgram* program, const Filt break; } } -#endif void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned exposedEdges) { @@ -523,13 +418,21 @@ void TextureMapperGL::drawTexture(const BitmapTexture& texture, const FloatRect& return; const BitmapTextureGL& textureGL = static_cast<const BitmapTextureGL&>(texture); -#if ENABLE(CSS_FILTERS) - TemporaryChange<const BitmapTextureGL::FilterInfo*> filterInfo(data().filterInfo, textureGL.filterInfo()); -#endif + SetForScope<const BitmapTextureGL::FilterInfo*> filterInfo(data().filterInfo, textureGL.filterInfo()); drawTexture(textureGL.id(), textureGL.isOpaque() ? 0 : ShouldBlend, textureGL.size(), targetRect, matrix, opacity, exposedEdges); } +static bool driverSupportsNPOTTextures(GraphicsContext3D& context) +{ + if (context.isGLES2Compliant()) { + static bool supportsNPOTTextures = context.getExtensions().supports("GL_OES_texture_npot"); + return supportsNPOTTextures; + } + + return true; +} + void TextureMapperGL::drawTexture(Platform3DObject texture, Flags flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, unsigned exposedEdges) { bool useRect = flags & ShouldUseARBTextureRect; @@ -546,8 +449,9 @@ void TextureMapperGL::drawTexture(Platform3DObject texture, Flags flags, const I options |= TextureMapperShaderProgram::Antialiasing; flags |= ShouldAntialias; } + if (wrapMode() == RepeatWrap && !driverSupportsNPOTTextures(*m_context3D)) + options |= TextureMapperShaderProgram::ManualRepeat; -#if ENABLE(CSS_FILTERS) RefPtr<FilterOperation> filter = data().filterInfo ? data().filterInfo->filter: 0; GC3Duint filterContentTextureID = 0; @@ -558,18 +462,14 @@ void TextureMapperGL::drawTexture(Platform3DObject texture, Flags flags, const I if (filter->affectsOpacity()) flags |= ShouldBlend; } -#endif if (useAntialiasing || opacity < 1) flags |= ShouldBlend; - RefPtr<TextureMapperShaderProgram> program; - program = data().sharedGLData().getShaderProgram(options); + Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options); -#if ENABLE(CSS_FILTERS) if (filter) prepareFilterProgram(program.get(), *filter.get(), data().filterInfo->pass, textureSize, filterContentTextureID); -#endif drawTexturedQuadWithProgram(program.get(), texture, flags, textureSize, targetRect, modelViewMatrix, opacity); } @@ -583,7 +483,7 @@ void TextureMapperGL::drawSolidColor(const FloatRect& rect, const Transformation flags |= ShouldBlend | ShouldAntialias; } - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options); + Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options); m_context3D->useProgram(program->programID()); float r, g, b, a; @@ -595,7 +495,7 @@ void TextureMapperGL::drawSolidColor(const FloatRect& rect, const Transformation draw(rect, matrix, program.get(), GraphicsContext3D::TRIANGLE_FAN, flags); } -void TextureMapperGL::drawEdgeTriangles(TextureMapperShaderProgram* program) +void TextureMapperGL::drawEdgeTriangles(TextureMapperShaderProgram& program) { const GC3Dfloat left = 0; const GC3Dfloat top = 0; @@ -620,29 +520,29 @@ void TextureMapperGL::drawEdgeTriangles(TextureMapperShaderProgram* program) Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 48, unitRectSideTriangles); m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo); - m_context3D->vertexAttribPointer(program->vertexLocation(), 4, GraphicsContext3D::FLOAT, false, 0, 0); + m_context3D->vertexAttribPointer(program.vertexLocation(), 4, GraphicsContext3D::FLOAT, false, 0, 0); m_context3D->drawArrays(GraphicsContext3D::TRIANGLES, 0, 12); m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); } -void TextureMapperGL::drawUnitRect(TextureMapperShaderProgram* program, GC3Denum drawingMode) +void TextureMapperGL::drawUnitRect(TextureMapperShaderProgram& program, GC3Denum drawingMode) { static const GC3Dfloat unitRect[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 8, unitRect); m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo); - m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, 0); + m_context3D->vertexAttribPointer(program.vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, 0); m_context3D->drawArrays(drawingMode, 0, 4); m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); } -void TextureMapperGL::draw(const FloatRect& rect, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram* shaderProgram, GC3Denum drawingMode, Flags flags) +void TextureMapperGL::draw(const FloatRect& rect, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram& program, GC3Denum drawingMode, Flags flags) { - TransformationMatrix matrix = - TransformationMatrix(modelViewMatrix).multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), rect)); + TransformationMatrix matrix(modelViewMatrix); + matrix.multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), rect)); - m_context3D->enableVertexAttribArray(shaderProgram->vertexLocation()); - shaderProgram->setMatrix(shaderProgram->modelViewMatrixLocation(), matrix); - shaderProgram->setMatrix(shaderProgram->projectionMatrixLocation(), data().projectionMatrix); + m_context3D->enableVertexAttribArray(program.vertexLocation()); + program.setMatrix(program.modelViewMatrixLocation(), matrix); + program.setMatrix(program.projectionMatrixLocation(), data().projectionMatrix); if (isInMaskMode()) { m_context3D->blendFunc(GraphicsContext3D::ZERO, GraphicsContext3D::SRC_ALPHA); @@ -656,28 +556,40 @@ void TextureMapperGL::draw(const FloatRect& rect, const TransformationMatrix& mo } if (flags & ShouldAntialias) - drawEdgeTriangles(shaderProgram); + drawEdgeTriangles(program); else - drawUnitRect(shaderProgram, drawingMode); + drawUnitRect(program, drawingMode); - m_context3D->disableVertexAttribArray(shaderProgram->vertexLocation()); + m_context3D->disableVertexAttribArray(program.vertexLocation()); m_context3D->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA); m_context3D->enable(GraphicsContext3D::BLEND); } -void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* program, uint32_t texture, Flags flags, const IntSize& size, const FloatRect& rect, const TransformationMatrix& modelViewMatrix, float opacity) +void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram& program, uint32_t texture, Flags flags, const IntSize& size, const FloatRect& rect, const TransformationMatrix& modelViewMatrix, float opacity) { - m_context3D->useProgram(program->programID()); + m_context3D->useProgram(program.programID()); m_context3D->activeTexture(GraphicsContext3D::TEXTURE0); GC3Denum target = flags & ShouldUseARBTextureRect ? GC3Denum(Extensions3D::TEXTURE_RECTANGLE_ARB) : GC3Denum(GraphicsContext3D::TEXTURE_2D); m_context3D->bindTexture(target, texture); - m_context3D->uniform1i(program->samplerLocation(), 0); - if (wrapMode() == RepeatWrap) { + m_context3D->uniform1i(program.samplerLocation(), 0); + if (wrapMode() == RepeatWrap && driverSupportsNPOTTextures(*m_context3D)) { m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::REPEAT); m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::REPEAT); } TransformationMatrix patternTransform = this->patternTransform(); + if (flags & ShouldRotateTexture90) { + patternTransform.rotate(-90); + patternTransform.translate(-1, 0); + } + if (flags & ShouldRotateTexture180) { + patternTransform.rotate(180); + patternTransform.translate(-1, -1); + } + if (flags & ShouldRotateTexture270) { + patternTransform.rotate(-270); + patternTransform.translate(0, -1); + } if (flags & ShouldFlipTexture) patternTransform.flipY(); if (flags & ShouldUseARBTextureRect) @@ -685,8 +597,8 @@ void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* pr if (flags & ShouldFlipTexture) patternTransform.translate(0, -1); - program->setMatrix(program->textureSpaceMatrixLocation(), patternTransform); - m_context3D->uniform1f(program->opacityLocation(), opacity); + program.setMatrix(program.textureSpaceMatrixLocation(), patternTransform); + m_context3D->uniform1f(program.opacityLocation(), opacity); if (opacity < 1) flags |= ShouldBlend; @@ -696,225 +608,17 @@ void TextureMapperGL::drawTexturedQuadWithProgram(TextureMapperShaderProgram* pr m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); } -BitmapTextureGL::BitmapTextureGL(TextureMapperGL* textureMapper) - : m_id(0) - , m_fbo(0) - , m_rbo(0) - , m_depthBufferObject(0) - , m_shouldClear(true) - , m_context3D(textureMapper->graphicsContext3D()) -{ -} - -bool BitmapTextureGL::canReuseWith(const IntSize& contentsSize, Flags) -{ - return contentsSize == m_textureSize; -} - -#if OS(DARWIN) -#define DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE GL_UNSIGNED_INT_8_8_8_8_REV -#else -#define DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE GraphicsContext3D::UNSIGNED_BYTE -#endif - -static void swizzleBGRAToRGBA(uint32_t* data, const IntRect& rect, int stride = 0) -{ - stride = stride ? stride : rect.width(); - for (int y = rect.y(); y < rect.maxY(); ++y) { - uint32_t* p = data + y * stride; - for (int x = rect.x(); x < rect.maxX(); ++x) - p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); - } -} - -// If GL_EXT_texture_format_BGRA8888 is supported in the OpenGLES -// internal and external formats need to be BGRA -static bool driverSupportsExternalTextureBGRA(GraphicsContext3D* context) -{ - if (context->isGLES2Compliant()) { - static bool supportsExternalTextureBGRA = context->getExtensions()->supports("GL_EXT_texture_format_BGRA8888"); - return supportsExternalTextureBGRA; - } - - return true; -} - -static bool driverSupportsSubImage(GraphicsContext3D* context) -{ - if (context->isGLES2Compliant()) { - static bool supportsSubImage = context->getExtensions()->supports("GL_EXT_unpack_subimage"); - return supportsSubImage; - } - - return true; -} - -void BitmapTextureGL::didReset() -{ - if (!m_id) - m_id = m_context3D->createTexture(); - - m_shouldClear = true; - if (m_textureSize == contentSize()) - return; - - - m_textureSize = contentSize(); - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); - m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR); - m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR); - m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); - m_context3D->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); - - Platform3DObject internalFormat = GraphicsContext3D::RGBA; - Platform3DObject externalFormat = GraphicsContext3D::BGRA; - if (m_context3D->isGLES2Compliant()) { - if (driverSupportsExternalTextureBGRA(m_context3D.get())) - internalFormat = GraphicsContext3D::BGRA; - else - externalFormat = GraphicsContext3D::RGBA; - } - - m_context3D->texImage2DDirect(GraphicsContext3D::TEXTURE_2D, 0, internalFormat, m_textureSize.width(), m_textureSize.height(), 0, externalFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, 0); -} - -void BitmapTextureGL::updateContentsNoSwizzle(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel, Platform3DObject glFormat) -{ - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); - if (driverSupportsSubImage(m_context3D.get())) { // For ES drivers that don't support sub-images. - // Use the OpenGL sub-image extension, now that we know it's available. - m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, bytesPerLine / bytesPerPixel); - m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, sourceOffset.y()); - m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, sourceOffset.x()); - } - - m_context3D->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(), glFormat, DEFAULT_TEXTURE_PIXEL_TRANSFER_TYPE, srcData); - - if (driverSupportsSubImage(m_context3D.get())) { // For ES drivers that don't support sub-images. - m_context3D->pixelStorei(GL_UNPACK_ROW_LENGTH, 0); - m_context3D->pixelStorei(GL_UNPACK_SKIP_ROWS, 0); - m_context3D->pixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - } -} - -void BitmapTextureGL::updateContents(const void* srcData, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag updateContentsFlag) -{ - Platform3DObject glFormat = GraphicsContext3D::RGBA; - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, m_id); - - const unsigned bytesPerPixel = 4; - char* data = reinterpret_cast<char*>(const_cast<void*>(srcData)); - Vector<char> temporaryData; - IntPoint adjustedSourceOffset = sourceOffset; - - // Texture upload requires subimage buffer if driver doesn't support subimage and we don't have full image upload. - bool requireSubImageBuffer = !driverSupportsSubImage(m_context3D.get()) - && !(bytesPerLine == static_cast<int>(targetRect.width() * bytesPerPixel) && adjustedSourceOffset == IntPoint::zero()); - - // prepare temporaryData if necessary - if ((!driverSupportsExternalTextureBGRA(m_context3D.get()) && updateContentsFlag == UpdateCannotModifyOriginalImageData) || requireSubImageBuffer) { - temporaryData.resize(targetRect.width() * targetRect.height() * bytesPerPixel); - data = temporaryData.data(); - const char* bits = static_cast<const char*>(srcData); - const char* src = bits + sourceOffset.y() * bytesPerLine + sourceOffset.x() * bytesPerPixel; - char* dst = data; - const int targetBytesPerLine = targetRect.width() * bytesPerPixel; - for (int y = 0; y < targetRect.height(); ++y) { - memcpy(dst, src, targetBytesPerLine); - src += bytesPerLine; - dst += targetBytesPerLine; - } - - bytesPerLine = targetBytesPerLine; - adjustedSourceOffset = IntPoint(0, 0); - } - - if (driverSupportsExternalTextureBGRA(m_context3D.get())) - glFormat = GraphicsContext3D::BGRA; - else - swizzleBGRAToRGBA(reinterpret_cast_ptr<uint32_t*>(data), IntRect(adjustedSourceOffset, targetRect.size()), bytesPerLine / bytesPerPixel); - - updateContentsNoSwizzle(data, targetRect, adjustedSourceOffset, bytesPerLine, bytesPerPixel, glFormat); -} - -void BitmapTextureGL::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag) -{ - if (!image) - return; - NativeImagePtr frameImage = image->nativeImageForCurrentFrame(); - if (!frameImage) - return; - - int bytesPerLine; - const char* imageData; - -#if USE(CAIRO) - cairo_surface_t* surface = frameImage.get(); - imageData = reinterpret_cast<const char*>(cairo_image_surface_get_data(surface)); - bytesPerLine = cairo_image_surface_get_stride(surface); -#endif - - updateContents(imageData, targetRect, offset, bytesPerLine, updateContentsFlag); -} - -#if ENABLE(CSS_FILTERS) void TextureMapperGL::drawFiltered(const BitmapTexture& sampler, const BitmapTexture* contentTexture, const FilterOperation& filter, int pass) { // For standard filters, we always draw the whole texture without transformations. TextureMapperShaderProgram::Options options = optionsForFilterType(filter.type(), pass); - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(options); - ASSERT(program); + Ref<TextureMapperShaderProgram> program = data().getShaderProgram(options); prepareFilterProgram(program.get(), filter, pass, sampler.contentSize(), contentTexture ? static_cast<const BitmapTextureGL*>(contentTexture)->id() : 0); FloatRect targetRect(IntPoint::zero(), sampler.contentSize()); drawTexturedQuadWithProgram(program.get(), static_cast<const BitmapTextureGL&>(sampler).id(), 0, IntSize(1, 1), targetRect, TransformationMatrix(), 1); } -PassRefPtr<BitmapTexture> BitmapTextureGL::applyFilters(TextureMapper* textureMapper, const FilterOperations& filters) -{ - if (filters.isEmpty()) - return this; - - TextureMapperGL* texmapGL = static_cast<TextureMapperGL*>(textureMapper); - RefPtr<BitmapTexture> previousSurface = texmapGL->data().currentSurface; - RefPtr<BitmapTexture> resultSurface = this; - RefPtr<BitmapTexture> intermediateSurface; - RefPtr<BitmapTexture> spareSurface; - - m_filterInfo = FilterInfo(); - - for (size_t i = 0; i < filters.size(); ++i) { - RefPtr<FilterOperation> filter = filters.operations()[i]; - ASSERT(filter); - - int numPasses = getPassesRequiredForFilter(filter->type()); - for (int j = 0; j < numPasses; ++j) { - bool last = (i == filters.size() - 1) && (j == numPasses - 1); - if (!last) { - if (!intermediateSurface) - intermediateSurface = texmapGL->acquireTextureFromPool(contentSize()); - texmapGL->bindSurface(intermediateSurface.get()); - } - - if (last) { - toBitmapTextureGL(resultSurface.get())->m_filterInfo = BitmapTextureGL::FilterInfo(filter, j, spareSurface); - break; - } - - texmapGL->drawFiltered(*resultSurface.get(), spareSurface.get(), *filter, j); - if (!j && filter->type() == FilterOperation::DROP_SHADOW) { - spareSurface = resultSurface; - resultSurface.clear(); - } - std::swap(resultSurface, intermediateSurface); - } - } - - texmapGL->bindSurface(previousSurface.get()); - return resultSurface; -} -#endif - static inline TransformationMatrix createProjectionMatrix(const IntSize& size, bool mirrored) { const float nearValue = 9999999; @@ -926,95 +630,6 @@ static inline TransformationMatrix createProjectionMatrix(const IntSize& size, b -1, mirrored ? -1 : 1, -(farValue + nearValue) / (farValue - nearValue), 1); } -void BitmapTextureGL::initializeStencil() -{ - if (m_rbo) - return; - - m_rbo = m_context3D->createRenderbuffer(); - m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_rbo); -#ifdef TEXMAP_OPENGL_ES_2 - m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_textureSize.width(), m_textureSize.height()); -#else - m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_STENCIL, m_textureSize.width(), m_textureSize.height()); -#endif - m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); - m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_rbo); - m_context3D->clearStencil(0); - m_context3D->clear(GraphicsContext3D::STENCIL_BUFFER_BIT); -} - -void BitmapTextureGL::initializeDepthBuffer() -{ - if (m_depthBufferObject) - return; - - m_depthBufferObject = m_context3D->createRenderbuffer(); - m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBufferObject); - m_context3D->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_textureSize.width(), m_textureSize.height()); - m_context3D->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); - m_context3D->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBufferObject); -} - -void BitmapTextureGL::clearIfNeeded() -{ - if (!m_shouldClear) - return; - - m_clipStack.reset(IntRect(IntPoint::zero(), m_textureSize), TextureMapperGL::ClipStack::DefaultYAxis); - m_clipStack.applyIfNeeded(m_context3D.get()); - m_context3D->clearColor(0, 0, 0, 0); - m_context3D->clear(GraphicsContext3D::COLOR_BUFFER_BIT); - m_shouldClear = false; -} - -void BitmapTextureGL::createFboIfNeeded() -{ - if (m_fbo) - return; - - m_fbo = m_context3D->createFramebuffer(); - m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); - m_context3D->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, id(), 0); - m_shouldClear = true; -} - -void BitmapTextureGL::bind(TextureMapperGL* textureMapper) -{ - m_context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); - createFboIfNeeded(); - m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); - m_context3D->viewport(0, 0, m_textureSize.width(), m_textureSize.height()); - clearIfNeeded(); - textureMapper->data().projectionMatrix = createProjectionMatrix(m_textureSize, true /* mirrored */); - m_clipStack.apply(m_context3D.get()); -} - -BitmapTextureGL::~BitmapTextureGL() -{ - if (m_id) - m_context3D->deleteTexture(m_id); - - if (m_fbo) - m_context3D->deleteFramebuffer(m_fbo); - - if (m_rbo) - m_context3D->deleteRenderbuffer(m_rbo); - - if (m_depthBufferObject) - m_context3D->deleteRenderbuffer(m_depthBufferObject); -} - -bool BitmapTextureGL::isValid() const -{ - return m_id; -} - -IntSize BitmapTextureGL::size() const -{ - return m_textureSize; -} - TextureMapperGL::~TextureMapperGL() { delete m_data; @@ -1023,11 +638,11 @@ TextureMapperGL::~TextureMapperGL() void TextureMapperGL::bindDefaultSurface() { m_context3D->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, data().targetFrameBuffer); - IntSize viewportSize(data().viewport[2], data().viewport[3]); - data().projectionMatrix = createProjectionMatrix(viewportSize, data().PaintFlags & PaintingMirrored); - m_context3D->viewport(data().viewport[0], data().viewport[1], viewportSize.width(), viewportSize.height()); - m_clipStack.apply(m_context3D.get()); - data().currentSurface.clear(); + auto& viewport = data().viewport; + data().projectionMatrix = createProjectionMatrix(IntSize(viewport[2], viewport[3]), data().PaintFlags & PaintingMirrored); + m_context3D->viewport(viewport[0], viewport[1], viewport[2], viewport[3]); + m_clipStack.apply(*m_context3D); + data().currentSurface = nullptr; } void TextureMapperGL::bindSurface(BitmapTexture *surface) @@ -1037,10 +652,16 @@ void TextureMapperGL::bindSurface(BitmapTexture *surface) return; } - static_cast<BitmapTextureGL*>(surface)->bind(this); + static_cast<BitmapTextureGL*>(surface)->bindAsSurface(m_context3D.get()); + data().projectionMatrix = createProjectionMatrix(surface->size(), true /* mirrored */); data().currentSurface = surface; } +BitmapTexture* TextureMapperGL::currentSurface() +{ + return data().currentSurface.get(); +} + bool TextureMapperGL::beginScissorClip(const TransformationMatrix& modelViewMatrix, const FloatRect& targetRect) { // 3D transforms are currently not supported in scissor clipping @@ -1056,7 +677,7 @@ bool TextureMapperGL::beginScissorClip(const TransformationMatrix& modelViewMatr return false; clipStack().intersect(rect); - clipStack().applyIfNeeded(m_context3D.get()); + clipStack().applyIfNeeded(*m_context3D); return true; } @@ -1068,15 +689,17 @@ void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, con data().initializeStencil(); - RefPtr<TextureMapperShaderProgram> program = data().sharedGLData().getShaderProgram(TextureMapperShaderProgram::SolidColor); + Ref<TextureMapperShaderProgram> program = data().getShaderProgram(TextureMapperShaderProgram::SolidColor); m_context3D->useProgram(program->programID()); m_context3D->enableVertexAttribArray(program->vertexLocation()); const GC3Dfloat unitRect[] = {0, 0, 1, 0, 1, 1, 0, 1}; - m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, GC3Dintptr(unitRect)); + Platform3DObject vbo = data().getStaticVBO(GraphicsContext3D::ARRAY_BUFFER, sizeof(GC3Dfloat) * 8, unitRect); + m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, vbo); + m_context3D->vertexAttribPointer(program->vertexLocation(), 2, GraphicsContext3D::FLOAT, false, 0, 0); - TransformationMatrix matrix = TransformationMatrix(modelViewMatrix) - .multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect)); + TransformationMatrix matrix(modelViewMatrix); + matrix.multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect)); static const TransformationMatrix fullProjectionMatrix = TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), FloatRect(-1, -1, 2, 2)); @@ -1103,18 +726,19 @@ void TextureMapperGL::beginClip(const TransformationMatrix& modelViewMatrix, con m_context3D->drawArrays(GraphicsContext3D::TRIANGLE_FAN, 0, 4); // Clear the state. + m_context3D->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); m_context3D->disableVertexAttribArray(program->vertexLocation()); m_context3D->stencilMask(0); // Increase stencilIndex and apply stencil testing. clipStack().setStencilIndex(stencilIndex * 2); - clipStack().applyIfNeeded(m_context3D.get()); + clipStack().applyIfNeeded(*m_context3D); } void TextureMapperGL::endClip() { clipStack().pop(); - clipStack().applyIfNeeded(m_context3D.get()); + clipStack().applyIfNeeded(*m_context3D); } IntRect TextureMapperGL::clipBounds() @@ -1124,14 +748,14 @@ IntRect TextureMapperGL::clipBounds() PassRefPtr<BitmapTexture> TextureMapperGL::createTexture() { - BitmapTextureGL* texture = new BitmapTextureGL(this); - return adoptRef(texture); + return BitmapTextureGL::create(*m_context3D); } -PassOwnPtr<TextureMapper> TextureMapper::platformCreateAccelerated() +std::unique_ptr<TextureMapper> TextureMapper::platformCreateAccelerated() { - return TextureMapperGL::create(); + return std::make_unique<TextureMapperGL>(); } }; -#endif + +#endif // USE(TEXTURE_MAPPER_GL) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h index 081403f00..acc78e8c8 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperGL.h @@ -1,5 +1,6 @@ /* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2015 Igalia S.L. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -20,8 +21,9 @@ #ifndef TextureMapperGL_h #define TextureMapperGL_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) +#if USE(TEXTURE_MAPPER_GL) +#include "ClipStack.h" #include "FilterOperation.h" #include "FloatQuad.h" #include "GraphicsContext3D.h" @@ -38,95 +40,49 @@ class FilterOperation; // An OpenGL-ES2 implementation of TextureMapper. class TextureMapperGL : public TextureMapper { public: - static PassOwnPtr<TextureMapperGL> create() { return adoptPtr(new TextureMapperGL); } + TextureMapperGL(); virtual ~TextureMapperGL(); enum Flag { ShouldBlend = 0x01, ShouldFlipTexture = 0x02, ShouldUseARBTextureRect = 0x04, - ShouldAntialias = 0x08 + ShouldAntialias = 0x08, + ShouldRotateTexture90 = 0x10, + ShouldRotateTexture180 = 0x20, + ShouldRotateTexture270 = 0x40 }; typedef int Flags; // TextureMapper implementation - virtual void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) override; - virtual void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) override; - virtual void drawTexture(const BitmapTexture&, const FloatRect&, const TransformationMatrix&, float opacity, unsigned exposedEdges) override; + void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) override; + void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) override; + void drawTexture(const BitmapTexture&, const FloatRect&, const TransformationMatrix&, float opacity, unsigned exposedEdges) override; virtual void drawTexture(Platform3DObject texture, Flags, const IntSize& textureSize, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity, unsigned exposedEdges = AllEdges); - virtual void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) override; - - virtual void bindSurface(BitmapTexture* surface) override; - virtual void beginClip(const TransformationMatrix&, const FloatRect&) override; - virtual void beginPainting(PaintFlags = 0) override; - virtual void endPainting() override; - virtual void endClip() override; - virtual IntRect clipBounds() override; - virtual IntSize maxTextureSize() const override { return IntSize(2000, 2000); } - virtual PassRefPtr<BitmapTexture> createTexture() override; + void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) override; + + void bindSurface(BitmapTexture* surface) override; + BitmapTexture* currentSurface(); + void beginClip(const TransformationMatrix&, const FloatRect&) override; + void beginPainting(PaintFlags = 0) override; + void endPainting() override; + void endClip() override; + IntRect clipBounds() override; + IntSize maxTextureSize() const override { return IntSize(2000, 2000); } + PassRefPtr<BitmapTexture> createTexture() override; inline GraphicsContext3D* graphicsContext3D() const { return m_context3D.get(); } -#if ENABLE(CSS_FILTERS) void drawFiltered(const BitmapTexture& sourceTexture, const BitmapTexture* contentTexture, const FilterOperation&, int pass); -#endif void setEnableEdgeDistanceAntialiasing(bool enabled) { m_enableEdgeDistanceAntialiasing = enabled; } private: - struct ClipState { - IntRect scissorBox; - int stencilIndex; - ClipState(const IntRect& scissors = IntRect(), int stencil = 1) - : scissorBox(scissors) - , stencilIndex(stencil) - { } - }; - - class ClipStack { - public: - ClipStack() - : clipStateDirty(false) - { } - - // Y-axis should be inverted only when painting into the window. - enum YAxisMode { - DefaultYAxis, - InvertedYAxis - }; - - void push(); - void pop(); - void apply(GraphicsContext3D*); - void applyIfNeeded(GraphicsContext3D*); - inline ClipState& current() { return clipState; } - void reset(const IntRect&, YAxisMode); - void intersect(const IntRect&); - void setStencilIndex(int); - inline int getStencilIndex() const - { - return clipState.stencilIndex; - } - inline bool isCurrentScissorBoxEmpty() const - { - return clipState.scissorBox.isEmpty(); - } - - private: - ClipState clipState; - Vector<ClipState> clipStack; - bool clipStateDirty; - IntSize size; - YAxisMode yAxisMode; - }; - - TextureMapperGL(); - - void drawTexturedQuadWithProgram(TextureMapperShaderProgram*, uint32_t texture, Flags, const IntSize&, const FloatRect&, const TransformationMatrix& modelViewMatrix, float opacity); - void draw(const FloatRect&, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram*, GC3Denum drawingMode, Flags); + void drawTexturedQuadWithProgram(TextureMapperShaderProgram&, uint32_t texture, Flags, const IntSize&, const FloatRect&, const TransformationMatrix& modelViewMatrix, float opacity); + void draw(const FloatRect&, const TransformationMatrix& modelViewMatrix, TextureMapperShaderProgram&, GC3Denum drawingMode, Flags); - void drawUnitRect(TextureMapperShaderProgram*, GC3Denum drawingMode); - void drawEdgeTriangles(TextureMapperShaderProgram*); + void drawUnitRect(TextureMapperShaderProgram&, GC3Denum drawingMode); + void drawEdgeTriangles(TextureMapperShaderProgram&); bool beginScissorClip(const TransformationMatrix&, const FloatRect&); void bindDefaultSurface(); @@ -136,72 +92,10 @@ private: TextureMapperGLData* m_data; ClipStack m_clipStack; bool m_enableEdgeDistanceAntialiasing; - - friend class BitmapTextureGL; -}; - -class BitmapTextureGL : public BitmapTexture { -public: - virtual IntSize size() const; - virtual bool isValid() const; - virtual bool canReuseWith(const IntSize& contentsSize, Flags = 0); - virtual void didReset(); - void bind(TextureMapperGL*); - void initializeStencil(); - void initializeDepthBuffer(); - ~BitmapTextureGL(); - virtual uint32_t id() const { return m_id; } - uint32_t textureTarget() const { return GraphicsContext3D::TEXTURE_2D; } - IntSize textureSize() const { return m_textureSize; } - void updateContents(Image*, const IntRect&, const IntPoint&, UpdateContentsFlag); - virtual void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag); - virtual bool isBackedByOpenGL() const { return true; } - -#if ENABLE(CSS_FILTERS) - virtual PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const FilterOperations&) override; - struct FilterInfo { - RefPtr<FilterOperation> filter; - unsigned pass; - RefPtr<BitmapTexture> contentTexture; - - FilterInfo(PassRefPtr<FilterOperation> f = 0, unsigned p = 0, PassRefPtr<BitmapTexture> t = 0) - : filter(f) - , pass(p) - , contentTexture(t) - { } - }; - const FilterInfo* filterInfo() const { return &m_filterInfo; } -#endif - -private: - void updateContentsNoSwizzle(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, unsigned bytesPerPixel = 4, Platform3DObject glFormat = GraphicsContext3D::RGBA); - - Platform3DObject m_id; - IntSize m_textureSize; - IntRect m_dirtyRect; - Platform3DObject m_fbo; - Platform3DObject m_rbo; - Platform3DObject m_depthBufferObject; - bool m_shouldClear; - TextureMapperGL::ClipStack m_clipStack; - RefPtr<GraphicsContext3D> m_context3D; - - explicit BitmapTextureGL(TextureMapperGL*); - BitmapTextureGL(); - - void clearIfNeeded(); - void createFboIfNeeded(); - -#if ENABLE(CSS_FILTERS) - FilterInfo m_filterInfo; -#endif - - friend class TextureMapperGL; }; -BitmapTextureGL* toBitmapTextureGL(BitmapTexture*); +} // namespace WebCore -} -#endif +#endif // USE(TEXTURE_MAPPER_GL) -#endif +#endif // TextureMapperGL_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp deleted file mode 100644 index 41041f91a..000000000 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "TextureMapperImageBuffer.h" - -#include "GraphicsLayer.h" -#include "NotImplemented.h" - -#if USE(TEXTURE_MAPPER) -namespace WebCore { - -static const int s_maximumAllowedImageBufferDimension = 4096; - -void BitmapTextureImageBuffer::updateContents(const void* data, const IntRect& targetRect, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag) -{ -#if PLATFORM(CAIRO) - RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create_for_data(static_cast<unsigned char*>(data()), - CAIRO_FORMAT_ARGB32, - targetRect.width(), targetRect.height(), - bytesPerLine)); - m_image->context()->platformContext()->drawSurfaceToContext(surface.get(), targetRect, - IntRect(sourceOffset, targetRect.size()), m_image->context()); -#else - UNUSED_PARAM(data); - UNUSED_PARAM(targetRect); - UNUSED_PARAM(sourceOffset); - UNUSED_PARAM(bytesPerLine); -#endif -} - -void BitmapTextureImageBuffer::updateContents(TextureMapper*, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& sourceOffset, UpdateContentsFlag) -{ - GraphicsContext* context = m_image->context(); - - context->clearRect(targetRect); - - IntRect sourceRect(targetRect); - sourceRect.setLocation(sourceOffset); - context->save(); - context->clip(targetRect); - context->translate(targetRect.x() - sourceOffset.x(), targetRect.y() - sourceOffset.y()); - sourceLayer->paintGraphicsLayerContents(*context, sourceRect); - context->restore(); -} - -void BitmapTextureImageBuffer::didReset() -{ - m_image = ImageBuffer::create(contentSize()); -} - -void BitmapTextureImageBuffer::updateContents(Image* image, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag) -{ - m_image->context()->drawImage(image, ColorSpaceDeviceRGB, targetRect, IntRect(offset, targetRect.size()), CompositeCopy, ImageOrientationDescription()); -} - -IntSize TextureMapperImageBuffer::maxTextureSize() const -{ - return IntSize(s_maximumAllowedImageBufferDimension, s_maximumAllowedImageBufferDimension); -} - -void TextureMapperImageBuffer::beginClip(const TransformationMatrix& matrix, const FloatRect& rect) -{ - GraphicsContext* context = currentContext(); - if (!context) - return; -#if ENABLE(3D_RENDERING) - TransformationMatrix previousTransform = context->get3DTransform(); -#else - AffineTransform previousTransform = context->getCTM(); -#endif - context->save(); - -#if ENABLE(3D_RENDERING) - context->concat3DTransform(matrix); -#else - context->concatCTM(matrix.toAffineTransform()); -#endif - - context->clip(rect); - -#if ENABLE(3D_RENDERING) - context->set3DTransform(previousTransform); -#else - context->setCTM(previousTransform); -#endif -} - -void TextureMapperImageBuffer::drawTexture(const BitmapTexture& texture, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity, unsigned /* exposedEdges */) -{ - GraphicsContext* context = currentContext(); - if (!context) - return; - - const BitmapTextureImageBuffer& textureImageBuffer = static_cast<const BitmapTextureImageBuffer&>(texture); - ImageBuffer* image = textureImageBuffer.m_image.get(); - context->save(); - context->setCompositeOperation(isInMaskMode() ? CompositeDestinationIn : CompositeSourceOver); - context->setAlpha(opacity); -#if ENABLE(3D_RENDERING) - context->concat3DTransform(matrix); -#else - context->concatCTM(matrix.toAffineTransform()); -#endif - context->drawImageBuffer(image, ColorSpaceDeviceRGB, targetRect); - context->restore(); -} - -void TextureMapperImageBuffer::drawSolidColor(const FloatRect& rect, const TransformationMatrix& matrix, const Color& color) -{ - GraphicsContext* context = currentContext(); - if (!context) - return; - - context->save(); - context->setCompositeOperation(isInMaskMode() ? CompositeDestinationIn : CompositeSourceOver); -#if ENABLE(3D_RENDERING) - context->concat3DTransform(matrix); -#else - context->concatCTM(matrix.toAffineTransform()); -#endif - - context->fillRect(rect, color, ColorSpaceDeviceRGB); - context->restore(); -} - -void TextureMapperImageBuffer::drawBorder(const Color&, float /* borderWidth */, const FloatRect&, const TransformationMatrix&) -{ - notImplemented(); -} - -void TextureMapperImageBuffer::drawNumber(int /* number */, const Color&, const FloatPoint&, const TransformationMatrix&) -{ - notImplemented(); -} - -#if ENABLE(CSS_FILTERS) -PassRefPtr<BitmapTexture> BitmapTextureImageBuffer::applyFilters(TextureMapper*, const FilterOperations&) -{ - ASSERT_NOT_REACHED(); - return this; -} -#endif - -} -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h deleted file mode 100644 index f5e38b358..000000000 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -#ifndef TextureMapperImageBuffer_h -#define TextureMapperImageBuffer_h - -#include "ImageBuffer.h" -#include "TextureMapper.h" - -#if USE(TEXTURE_MAPPER) -namespace WebCore { - -class BitmapTextureImageBuffer : public BitmapTexture { - friend class TextureMapperImageBuffer; -public: - static PassRefPtr<BitmapTexture> create() { return adoptRef(new BitmapTextureImageBuffer); } - virtual IntSize size() const { return m_image->internalSize(); } - virtual void didReset(); - virtual bool isValid() const { return m_image.get(); } - inline GraphicsContext* graphicsContext() { return m_image ? m_image->context() : 0; } - virtual void updateContents(Image*, const IntRect&, const IntPoint&, UpdateContentsFlag); - virtual void updateContents(TextureMapper*, GraphicsLayer*, const IntRect& target, const IntPoint& offset, UpdateContentsFlag); - virtual void updateContents(const void*, const IntRect& target, const IntPoint& sourceOffset, int bytesPerLine, UpdateContentsFlag); -#if ENABLE(CSS_FILTERS) - PassRefPtr<BitmapTexture> applyFilters(TextureMapper*, const FilterOperations&); -#endif - -private: - BitmapTextureImageBuffer() { } - std::unique_ptr<ImageBuffer> m_image; -}; - - -class TextureMapperImageBuffer : public TextureMapper { - WTF_MAKE_FAST_ALLOCATED; -public: - static PassOwnPtr<TextureMapper> create() { return adoptPtr(new TextureMapperImageBuffer); } - - // TextureMapper implementation - virtual void drawBorder(const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) override; - virtual void drawNumber(int number, const Color&, const FloatPoint&, const TransformationMatrix&) override; - virtual void drawTexture(const BitmapTexture&, const FloatRect& targetRect, const TransformationMatrix&, float opacity, unsigned exposedEdges) override; - virtual void drawSolidColor(const FloatRect&, const TransformationMatrix&, const Color&) override; - virtual void beginClip(const TransformationMatrix&, const FloatRect&) override; - virtual void bindSurface(BitmapTexture* surface) override { m_currentSurface = surface;} - virtual void endClip() override { graphicsContext()->restore(); } - virtual IntRect clipBounds() override { return currentContext()->clipBounds(); } - virtual IntSize maxTextureSize() const; - virtual PassRefPtr<BitmapTexture> createTexture() override { return BitmapTextureImageBuffer::create(); } - - inline GraphicsContext* currentContext() - { - return m_currentSurface ? static_cast<BitmapTextureImageBuffer*>(m_currentSurface.get())->graphicsContext() : graphicsContext(); - } - -private: - TextureMapperImageBuffer() - : TextureMapper(SoftwareMode) - { } - RefPtr<BitmapTexture> m_currentSurface; -}; - -} -#endif // USE(TEXTURE_MAPPER) - -#endif // TextureMapperImageBuffer_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp index 7e7babbcd..d39cffcbb 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp @@ -21,35 +21,25 @@ #include "TextureMapperLayer.h" #include "FloatQuad.h" +#include "GraphicsLayerTextureMapper.h" #include "Region.h" #include <wtf/MathExtras.h> -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - namespace WebCore { class TextureMapperPaintOptions { public: - RefPtr<BitmapTexture> surface; - float opacity; + TextureMapperPaintOptions(TextureMapper& textureMapper) + : textureMapper(textureMapper) + { } + + TextureMapper& textureMapper; TransformationMatrix transform; + RefPtr<BitmapTexture> surface; + float opacity { 1 }; IntSize offset; - TextureMapper* textureMapper; - TextureMapperPaintOptions() - : opacity(1) - , textureMapper(0) - { } }; -const TextureMapperLayer* TextureMapperLayer::rootLayer() const -{ - if (m_effectTarget) - return m_effectTarget->rootLayer(); - if (m_parent) - return m_parent->rootLayer(); - return this; -} - void TextureMapperLayer::computeTransformsRecursive() { if (m_state.size.isEmpty() && m_state.masksToBounds) @@ -72,9 +62,9 @@ void TextureMapperLayer::computeTransformsRecursive() m_state.maskLayer->computeTransformsRecursive(); if (m_state.replicaLayer) m_state.replicaLayer->computeTransformsRecursive(); - for (size_t i = 0; i < m_children.size(); ++i) { - RELEASE_ASSERT(m_children[i]->m_parent == this); - m_children[i]->computeTransformsRecursive(); + for (auto* child : m_children) { + ASSERT(child->m_parent == this); + child->computeTransformsRecursive(); } // Reorder children if needed on the way back up. @@ -86,19 +76,19 @@ void TextureMapperLayer::paint() { computeTransformsRecursive(); - TextureMapperPaintOptions options; - options.textureMapper = m_textureMapper; - options.textureMapper->bindSurface(0); + ASSERT(m_textureMapper); + TextureMapperPaintOptions options(*m_textureMapper); + options.textureMapper.bindSurface(0); + paintRecursive(options); } static Color blendWithOpacity(const Color& color, float opacity) { - RGBA32 rgba = color.rgb(); - // See Color::getRGBA() to know how to extract alpha from color. - float alpha = alphaChannel(rgba) / 255.; - float effectiveAlpha = alpha * opacity; - return Color(colorWithOverrideAlpha(rgba, effectiveAlpha)); + if (color.isOpaque() && opacity == 1.) + return color; + + return color.colorWithAlphaMultipliedBy(opacity); } void TextureMapperLayer::computePatternTransformIfNeeded() @@ -108,8 +98,8 @@ void TextureMapperLayer::computePatternTransformIfNeeded() m_patternTransformDirty = false; m_patternTransform = - TransformationMatrix::rectToRect(FloatRect(FloatPoint::zero(), m_state.contentsTileSize), m_state.contentsRect) - .multiply(TransformationMatrix().translate(m_state.contentsTilePhase.x() / m_state.contentsRect.width(), m_state.contentsTilePhase.y() / m_state.contentsRect.height())); + TransformationMatrix::rectToRect(FloatRect(FloatPoint::zero(), m_state.contentsTileSize), FloatRect(FloatPoint::zero(), m_state.contentsRect.size())) + .multiply(TransformationMatrix().translate(m_state.contentsTilePhase.width() / m_state.contentsRect.width(), m_state.contentsTilePhase.height() / m_state.contentsRect.height())); } void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options) @@ -123,15 +113,15 @@ void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options) transform.multiply(options.transform); transform.multiply(m_currentTransform.combined()); - if (m_state.solidColor.isValid() && !m_state.contentsRect.isEmpty() && m_state.solidColor.alpha()) { - options.textureMapper->drawSolidColor(m_state.contentsRect, transform, blendWithOpacity(m_state.solidColor, options.opacity)); + if (m_state.solidColor.isValid() && !m_state.contentsRect.isEmpty() && m_state.solidColor.isVisible()) { + options.textureMapper.drawSolidColor(m_state.contentsRect, transform, blendWithOpacity(m_state.solidColor, options.opacity)); if (m_state.showDebugBorders) - options.textureMapper->drawBorder(m_state.debugBorderColor, m_state.debugBorderWidth, layerRect(), transform); + options.textureMapper.drawBorder(m_state.debugBorderColor, m_state.debugBorderWidth, layerRect(), transform); return; } - options.textureMapper->setWrapMode(TextureMapper::StretchWrap); - options.textureMapper->setPatternTransform(TransformationMatrix()); + options.textureMapper.setWrapMode(TextureMapper::StretchWrap); + options.textureMapper.setPatternTransform(TransformationMatrix()); if (m_backingStore) { FloatRect targetRect = layerRect(); @@ -149,8 +139,8 @@ void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options) if (!m_state.contentsTileSize.isEmpty()) { computePatternTransformIfNeeded(); - options.textureMapper->setWrapMode(TextureMapper::RepeatWrap); - options.textureMapper->setPatternTransform(m_patternTransform); + options.textureMapper.setWrapMode(TextureMapper::RepeatWrap); + options.textureMapper.setPatternTransform(m_patternTransform); } ASSERT(!layerRect().isEmpty()); @@ -159,16 +149,12 @@ void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options) m_contentsLayer->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, m_state.contentsRect, transform); } -int TextureMapperLayer::compareGraphicsLayersZValue(const void* a, const void* b) -{ - TextureMapperLayer* const* layerA = static_cast<TextureMapperLayer* const*>(a); - TextureMapperLayer* const* layerB = static_cast<TextureMapperLayer* const*>(b); - return int(((*layerA)->m_centerZ - (*layerB)->m_centerZ) * 1000); -} - void TextureMapperLayer::sortByZOrder(Vector<TextureMapperLayer* >& array) { - qsort(array.data(), array.size(), sizeof(TextureMapperLayer*), compareGraphicsLayersZValue); + std::sort(array.begin(), array.end(), + [](TextureMapperLayer* a, TextureMapperLayer* b) { + return a->m_centerZ < b->m_centerZ; + }); } void TextureMapperLayer::paintSelfAndChildren(const TextureMapperPaintOptions& options) @@ -184,14 +170,14 @@ void TextureMapperLayer::paintSelfAndChildren(const TextureMapperPaintOptions& o clipTransform.translate(options.offset.width(), options.offset.height()); clipTransform.multiply(options.transform); clipTransform.multiply(m_currentTransform.combined()); - options.textureMapper->beginClip(clipTransform, layerRect()); + options.textureMapper.beginClip(clipTransform, layerRect()); } - for (size_t i = 0; i < m_children.size(); ++i) - m_children[i]->paintRecursive(options); + for (auto* child : m_children) + child->paintRecursive(options); if (shouldClip) - options.textureMapper->endClip(); + options.textureMapper.endClip(); } bool TextureMapperLayer::shouldBlend() const @@ -224,7 +210,7 @@ void TextureMapperLayer::paintSelfAndChildrenWithReplica(const TextureMapperPain TextureMapperPaintOptions replicaOptions(options); replicaOptions.transform .multiply(m_state.replicaLayer->m_currentTransform.combined()) - .multiply(m_currentTransform.combined().inverse()); + .multiply(m_currentTransform.combined().inverse().value_or(TransformationMatrix())); paintSelfAndChildren(replicaOptions); } @@ -243,17 +229,15 @@ void TextureMapperLayer::setAnimatedOpacity(float opacity) TransformationMatrix TextureMapperLayer::replicaTransform() { - return TransformationMatrix(m_state.replicaLayer->m_currentTransform.combined()).multiply(m_currentTransform.combined().inverse()); + return TransformationMatrix(m_state.replicaLayer->m_currentTransform.combined()).multiply(m_currentTransform.combined().inverse().value_or(TransformationMatrix())); } -#if ENABLE(CSS_FILTERS) void TextureMapperLayer::setAnimatedFilters(const FilterOperations& filters) { m_currentFilters = filters; } -#endif -static void resolveOverlaps(Region newRegion, Region& overlapRegion, Region& nonOverlapRegion) +static void resolveOverlaps(Region& newRegion, Region& overlapRegion, Region& nonOverlapRegion) { Region newOverlapRegion(newRegion); newOverlapRegion.intersect(nonOverlapRegion); @@ -271,10 +255,9 @@ void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& no FloatRect boundingRect; if (m_backingStore || m_state.masksToBounds || m_state.maskLayer || hasFilters()) boundingRect = layerRect(); - else if (m_contentsLayer || m_state.solidColor.alpha()) + else if (m_contentsLayer || m_state.solidColor.isVisible()) boundingRect = m_state.contentsRect; -#if ENABLE(CSS_FILTERS) if (m_currentFilters.hasOutsets()) { FilterOutsets outsets = m_currentFilters.outsets(); IntRect unfilteredTargetRect(boundingRect); @@ -282,7 +265,6 @@ void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& no boundingRect.expand(outsets.left() + outsets.right(), outsets.top() + outsets.bottom()); boundingRect.unite(unfilteredTargetRect); } -#endif TransformationMatrix replicaMatrix; if (m_state.replicaLayer) { @@ -304,10 +286,8 @@ void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& no Region newNonOverlapRegion(enclosingIntRect(boundingRect)); if (!m_state.masksToBounds) { - for (size_t i = 0; i < m_children.size(); ++i) { - TextureMapperLayer* child = m_children[i]; + for (auto* child : m_children) child->computeOverlapRegions(newOverlapRegion, newNonOverlapRegion, ResolveSelfOverlapIfNeeded); - } } if (m_state.replicaLayer) { @@ -345,14 +325,13 @@ void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOption nonOverlapRegion.translate(options.offset); Vector<IntRect> rects = nonOverlapRegion.rects(); - for (size_t i = 0; i < rects.size(); ++i) { - IntRect rect = rects[i]; - if (!rect.intersects(options.textureMapper->clipBounds())) + for (auto& rect : rects) { + if (!rect.intersects(options.textureMapper.clipBounds())) continue; - options.textureMapper->beginClip(TransformationMatrix(), rects[i]); + options.textureMapper.beginClip(TransformationMatrix(), rect); paintSelfAndChildrenWithReplica(options); - options.textureMapper->endClip(); + options.textureMapper.endClip(); } rects = overlapRegion.rects(); @@ -362,11 +341,10 @@ void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOption rects.append(overlapRegion.bounds()); } - IntSize maxTextureSize = options.textureMapper->maxTextureSize(); - IntRect adjustedClipBounds(options.textureMapper->clipBounds()); + IntSize maxTextureSize = options.textureMapper.maxTextureSize(); + IntRect adjustedClipBounds(options.textureMapper.clipBounds()); adjustedClipBounds.move(-options.offset); - for (size_t i = 0; i < rects.size(); ++i) { - IntRect rect = rects[i]; + for (auto& rect : rects) { for (int x = rect.x(); x < rect.maxX(); x += maxTextureSize.width()) { for (int y = rect.y(); y < rect.maxY(); y += maxTextureSize.height()) { IntRect tileRect(IntPoint(x, y), maxTextureSize); @@ -382,34 +360,32 @@ void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOption void TextureMapperLayer::applyMask(const TextureMapperPaintOptions& options) { - options.textureMapper->setMaskMode(true); + options.textureMapper.setMaskMode(true); paintSelf(options); - options.textureMapper->setMaskMode(false); + options.textureMapper.setMaskMode(false); } PassRefPtr<BitmapTexture> TextureMapperLayer::paintIntoSurface(const TextureMapperPaintOptions& options, const IntSize& size) { - RefPtr<BitmapTexture> surface = options.textureMapper->acquireTextureFromPool(size); + RefPtr<BitmapTexture> surface = options.textureMapper.acquireTextureFromPool(size, BitmapTexture::SupportsAlpha | BitmapTexture::FBOAttachment); TextureMapperPaintOptions paintOptions(options); paintOptions.surface = surface; - options.textureMapper->bindSurface(surface.get()); + options.textureMapper.bindSurface(surface.get()); paintSelfAndChildren(paintOptions); if (m_state.maskLayer) m_state.maskLayer->applyMask(options); -#if ENABLE(CSS_FILTERS) surface = surface->applyFilters(options.textureMapper, m_currentFilters); -#endif - options.textureMapper->bindSurface(surface.get()); - return surface; + options.textureMapper.bindSurface(surface.get()); + return surface.release(); } static void commitSurface(const TextureMapperPaintOptions& options, PassRefPtr<BitmapTexture> surface, const IntRect& rect, float opacity) { - options.textureMapper->bindSurface(options.surface.get()); + options.textureMapper.bindSurface(options.surface.get()); TransformationMatrix targetTransform; targetTransform.translate(options.offset.width(), options.offset.height()); targetTransform.multiply(options.transform); - options.textureMapper->drawTexture(*surface.get(), rect, targetTransform, opacity); + options.textureMapper.drawTexture(*surface.get(), rect, targetTransform, opacity); } void TextureMapperLayer::paintWithIntermediateSurface(const TextureMapperPaintOptions& options, const IntRect& rect) @@ -430,13 +406,13 @@ void TextureMapperLayer::paintWithIntermediateSurface(const TextureMapperPaintOp if (replicaSurface && options.opacity == 1) { commitSurface(options, replicaSurface, rect, 1); - replicaSurface.clear(); + replicaSurface = nullptr; } mainSurface = paintIntoSurface(paintOptions, rect.size()); if (replicaSurface) { - options.textureMapper->bindSurface(replicaSurface.get()); - options.textureMapper->drawTexture(*mainSurface.get(), FloatRect(FloatPoint::zero(), rect.size())); + options.textureMapper.bindSurface(replicaSurface.get()); + options.textureMapper.drawTexture(*mainSurface.get(), FloatRect(FloatPoint::zero(), rect.size())); mainSurface = replicaSurface; } @@ -461,23 +437,33 @@ void TextureMapperLayer::paintRecursive(const TextureMapperPaintOptions& options TextureMapperLayer::~TextureMapperLayer() { - for (int i = m_children.size() - 1; i >= 0; --i) - m_children[i]->m_parent = 0; + for (auto* child : m_children) + child->m_parent = nullptr; - if (m_parent) - m_parent->m_children.remove(m_parent->m_children.find(this)); + removeFromParent(); + + if (m_effectTarget) { + if (m_effectTarget->m_state.maskLayer == this) + m_effectTarget->m_state.maskLayer = nullptr; + if (m_effectTarget->m_state.replicaLayer == this) + m_effectTarget->m_state.replicaLayer = nullptr; + } } -TextureMapper* TextureMapperLayer::textureMapper() const +#if !USE(COORDINATED_GRAPHICS) +void TextureMapperLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) { - return rootLayer()->m_textureMapper; + removeAllChildren(); + for (auto* child : newChildren) + addChild(&downcast<GraphicsLayerTextureMapper>(child)->layer()); } +#endif void TextureMapperLayer::setChildren(const Vector<TextureMapperLayer*>& newChildren) { removeAllChildren(); - for (size_t i = 0; i < newChildren.size(); ++i) - addChild(newChildren[i]); + for (auto* child : newChildren) + addChild(child); } void TextureMapperLayer::addChild(TextureMapperLayer* childLayer) @@ -494,25 +480,19 @@ void TextureMapperLayer::addChild(TextureMapperLayer* childLayer) void TextureMapperLayer::removeFromParent() { if (m_parent) { - unsigned i; - for (i = 0; i < m_parent->m_children.size(); i++) { - if (this == m_parent->m_children[i]) { - m_parent->m_children.remove(i); - break; - } - } - - m_parent = 0; + size_t index = m_parent->m_children.find(this); + ASSERT(index != notFound); + m_parent->m_children.remove(index); } + + m_parent = nullptr; } void TextureMapperLayer::removeAllChildren() { - while (m_children.size()) { - TextureMapperLayer* curLayer = m_children[0]; - ASSERT(curLayer->m_parent); - curLayer->removeFromParent(); - } + auto oldChildren = WTFMove(m_children); + for (auto* child : oldChildren) + child->m_parent = nullptr; } void TextureMapperLayer::setMaskLayer(TextureMapperLayer* maskLayer) @@ -565,7 +545,7 @@ void TextureMapperLayer::setChildrenTransform(const TransformationMatrix& childr m_currentTransform.setChildrenTransform(childrenTransform); } -void TextureMapperLayer::setContentsRect(const IntRect& contentsRect) +void TextureMapperLayer::setContentsRect(const FloatRect& contentsRect) { if (contentsRect == m_state.contentsRect) return; @@ -573,7 +553,7 @@ void TextureMapperLayer::setContentsRect(const IntRect& contentsRect) m_patternTransformDirty = true; } -void TextureMapperLayer::setContentsTileSize(const IntSize& size) +void TextureMapperLayer::setContentsTileSize(const FloatSize& size) { if (size == m_state.contentsTileSize) return; @@ -581,7 +561,7 @@ void TextureMapperLayer::setContentsTileSize(const IntSize& size) m_patternTransformDirty = true; } -void TextureMapperLayer::setContentsTilePhase(const IntPoint& phase) +void TextureMapperLayer::setContentsTilePhase(const FloatSize& phase) { if (phase == m_state.contentsTilePhase) return; @@ -624,12 +604,10 @@ void TextureMapperLayer::setSolidColor(const Color& color) m_state.solidColor = color; } -#if ENABLE(CSS_FILTERS) void TextureMapperLayer::setFilters(const FilterOperations& filters) { m_state.filters = filters; } -#endif void TextureMapperLayer::setDebugVisuals(bool showDebugBorders, const Color& debugBorderColor, float debugBorderWidth, bool showRepaintCounter) { @@ -649,7 +627,7 @@ void TextureMapperLayer::setContentsLayer(TextureMapperPlatformLayer* platformLa m_contentsLayer = platformLayer; } -void TextureMapperLayer::setAnimations(const GraphicsLayerAnimations& animations) +void TextureMapperLayer::setAnimations(const TextureMapperAnimations& animations) { m_animations = animations; } @@ -669,33 +647,29 @@ bool TextureMapperLayer::descendantsOrSelfHaveRunningAnimations() const if (m_animations.hasRunningAnimations()) return true; - for (size_t i = 0; i < m_children.size(); ++i) { - if (m_children[i]->descendantsOrSelfHaveRunningAnimations()) - return true; - } - - return false; + return std::any_of(m_children.begin(), m_children.end(), + [](TextureMapperLayer* child) { + return child->descendantsOrSelfHaveRunningAnimations(); + }); } void TextureMapperLayer::applyAnimationsRecursively() { syncAnimations(); - for (size_t i = 0; i < m_children.size(); ++i) - m_children[i]->applyAnimationsRecursively(); + for (auto* child : m_children) + child->applyAnimationsRecursively(); } void TextureMapperLayer::syncAnimations() { - m_animations.apply(this); - if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform)) + m_animations.apply(*this); + if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyTransform)) m_currentTransform.setLocalTransform(m_state.transform); if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyOpacity)) m_currentOpacity = m_state.opacity; -#if ENABLE(CSS_FILTERS) - if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitFilter)) + if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyFilter)) m_currentFilters = m_state.filters; -#endif } bool TextureMapperLayer::isAncestorFixedToViewport() const @@ -756,7 +730,7 @@ TextureMapperLayer* TextureMapperLayer::findScrollableContentsLayerAt(const Floa FloatSize TextureMapperLayer::mapScrollOffset(const FloatSize& offset) { double zeroX, zeroY, offsetX, offsetY; - TransformationMatrix transform = m_currentTransform.combined().inverse(); + TransformationMatrix transform = m_currentTransform.combined().inverse().value_or(TransformationMatrix()); transform.map(0, 0, zeroX, zeroY); transform.map(offset.width(), offset.height(), offsetX, offsetY); return FloatSize(offsetX - zeroX, offsetY - zeroY); @@ -795,4 +769,3 @@ void TextureMapperLayer::didCommitScrollOffset(const IntSize& offset) } } -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h index 87ff3f4a7..3b1c16b0b 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperLayer.h @@ -20,22 +20,21 @@ #ifndef TextureMapperLayer_h #define TextureMapperLayer_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - #include "FilterOperations.h" #include "FloatRect.h" -#include "GraphicsLayerAnimation.h" #include "GraphicsLayerTransform.h" #include "TextureMapper.h" +#include "TextureMapperAnimation.h" #include "TextureMapperBackingStore.h" namespace WebCore { +class GraphicsLayer; class Region; class TextureMapperPaintOptions; class TextureMapperPlatformLayer; -class TextureMapperLayer : public GraphicsLayerAnimation::Client { +class TextureMapperLayer : public TextureMapperAnimation::Client { WTF_MAKE_NONCOPYABLE(TextureMapperLayer); WTF_MAKE_FAST_ALLOCATED; public: @@ -74,9 +73,12 @@ public: void setIsScrollable(bool isScrollable) { m_isScrollable = isScrollable; } bool isScrollable() const { return m_isScrollable; } - TextureMapper* textureMapper() const; + TextureMapper* textureMapper() const { return rootLayer().m_textureMapper; } void setTextureMapper(TextureMapper* texmap) { m_textureMapper = texmap; } +#if !USE(COORDINATED_GRAPHICS) + void setChildren(const Vector<GraphicsLayer*>&); +#endif void setChildren(const Vector<TextureMapperLayer*>&); void setMaskLayer(TextureMapperLayer*); void setReplicaLayer(TextureMapperLayer*); @@ -86,7 +88,7 @@ public: void setPreserves3D(bool); void setTransform(const TransformationMatrix&); void setChildrenTransform(const TransformationMatrix&); - void setContentsRect(const IntRect&); + void setContentsRect(const FloatRect&); void setMasksToBounds(bool); void setDrawsContent(bool); bool drawsContent() const { return m_state.drawsContent; } @@ -99,26 +101,20 @@ public: void setBackfaceVisibility(bool); void setOpacity(float); void setSolidColor(const Color&); - void setContentsTileSize(const IntSize&); - void setContentsTilePhase(const IntPoint&); -#if ENABLE(CSS_FILTERS) + void setContentsTileSize(const FloatSize&); + void setContentsTilePhase(const FloatSize&); void setFilters(const FilterOperations&); -#endif bool hasFilters() const { -#if ENABLE(CSS_FILTERS) return !m_currentFilters.isEmpty(); -#else - return false; -#endif } void setDebugVisuals(bool showDebugBorders, const Color& debugBorderColor, float debugBorderWidth, bool showRepaintCounter); bool isShowingRepaintCounter() const { return m_state.showRepaintCounter; } void setRepaintCount(int); void setContentsLayer(TextureMapperPlatformLayer*); - void setAnimations(const GraphicsLayerAnimations&); + void setAnimations(const TextureMapperAnimations&); void setFixedToViewport(bool); bool fixedToViewport() const { return m_fixedToViewport; } void setBackingStore(PassRefPtr<TextureMapperBackingStore>); @@ -134,13 +130,19 @@ public: void addChild(TextureMapperLayer*); private: - const TextureMapperLayer* rootLayer() const; + const TextureMapperLayer& rootLayer() const + { + if (m_effectTarget) + return m_effectTarget->rootLayer(); + if (m_parent) + return m_parent->rootLayer(); + return *this; + } void computeTransformsRecursive(); - static int compareGraphicsLayersZValue(const void* a, const void* b); static void sortByZOrder(Vector<TextureMapperLayer* >& array); - PassRefPtr<BitmapTexture> texture() { return m_backingStore ? m_backingStore->texture() : 0; } + RefPtr<BitmapTexture> texture() { return m_backingStore ? m_backingStore->texture() : 0; } FloatPoint adjustedPosition() const { return m_state.pos + m_scrollPositionDelta - m_userScrollOffset; } bool isAncestorFixedToViewport() const; TransformationMatrix replicaTransform(); @@ -163,12 +165,10 @@ private: void applyMask(const TextureMapperPaintOptions&); void computePatternTransformIfNeeded(); - // GraphicsLayerAnimation::Client - virtual void setAnimatedTransform(const TransformationMatrix&) override; - virtual void setAnimatedOpacity(float) override; -#if ENABLE(CSS_FILTERS) - virtual void setAnimatedFilters(const FilterOperations&) override; -#endif + // TextureMapperAnimation::Client + void setAnimatedTransform(const TransformationMatrix&) override; + void setAnimatedOpacity(float) override; + void setAnimatedFilters(const FilterOperations&) override; bool isVisible() const; enum ContentsLayerCount { @@ -191,9 +191,7 @@ private: TextureMapperPlatformLayer* m_contentsLayer; GraphicsLayerTransform m_currentTransform; float m_currentOpacity; -#if ENABLE(CSS_FILTERS) FilterOperations m_currentFilters; -#endif float m_centerZ; template<class HitTestCondition> TextureMapperLayer* hitTest(const FloatPoint&, HitTestCondition); @@ -210,14 +208,12 @@ private: TransformationMatrix childrenTransform; float opacity; FloatRect contentsRect; - IntSize contentsTileSize; - IntPoint contentsTilePhase; + FloatSize contentsTileSize; + FloatSize contentsTilePhase; TextureMapperLayer* maskLayer; TextureMapperLayer* replicaLayer; Color solidColor; -#if ENABLE(CSS_FILTERS) FilterOperations filters; -#endif Color debugBorderColor; float debugBorderWidth; int repaintCount; @@ -253,7 +249,7 @@ private: State m_state; TextureMapper* m_textureMapper; - GraphicsLayerAnimations m_animations; + TextureMapperAnimations m_animations; FloatSize m_scrollPositionDelta; bool m_fixedToViewport; uint32_t m_id; @@ -266,6 +262,5 @@ private: }; } -#endif #endif // TextureMapperLayer_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h index 2482e0e94..ddacbfd0a 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h @@ -20,9 +20,7 @@ #ifndef TextureMapperPlatformLayer_h #define TextureMapperPlatformLayer_h -#if USE(GRAPHICS_SURFACE) -#include "GraphicsSurface.h" -#endif +#if USE(TEXTURE_MAPPER) #include "TextureMapper.h" #include "TransformationMatrix.h" @@ -39,22 +37,16 @@ public: TextureMapperPlatformLayer() : m_client(0) { } virtual ~TextureMapperPlatformLayer() { } - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0) = 0; + virtual void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0) = 0; virtual void swapBuffers() { } - virtual void drawBorder(TextureMapper* textureMapper, const Color& color, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) + virtual void drawBorder(TextureMapper& textureMapper, const Color& color, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) { - textureMapper->drawBorder(color, borderWidth, targetRect, transform); + textureMapper.drawBorder(color, borderWidth, targetRect, transform); } void setClient(TextureMapperPlatformLayer::Client* client) { m_client = client; } -#if USE(GRAPHICS_SURFACE) - virtual IntSize platformLayerSize() const { return IntSize(); } - virtual uint32_t copyToGraphicsSurface() { return 0; } - virtual GraphicsSurfaceToken graphicsSurfaceToken() const { return GraphicsSurfaceToken(); } - virtual GraphicsSurface::Flags graphicsSurfaceFlags() const { return GraphicsSurface::SupportsTextureTarget | GraphicsSurface::SupportsSharing; } -#endif protected: TextureMapperPlatformLayer::Client* client() { return m_client; } @@ -65,4 +57,6 @@ private: }; +#endif // USE(TEXTURE_MAPPER) + #endif // TextureMapperPlatformLayer_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.cpp new file mode 100644 index 000000000..88851fe4b --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" +#include "TextureMapperPlatformLayerBuffer.h" + +namespace WebCore { + +TextureMapperPlatformLayerBuffer::TextureMapperPlatformLayerBuffer(RefPtr<BitmapTexture>&& texture) + : m_texture(WTFMove(texture)) + , m_textureID(0) + , m_extraFlags(0) + , m_hasManagedTexture(true) +{ +} + +TextureMapperPlatformLayerBuffer::TextureMapperPlatformLayerBuffer(GLuint textureID, const IntSize& size, TextureMapperGL::Flags flags) + : m_textureID(textureID) + , m_size(size) + , m_extraFlags(flags) + , m_hasManagedTexture(false) +{ +} + +bool TextureMapperPlatformLayerBuffer::canReuseWithoutReset(const IntSize& size, GC3Dint internalFormat) +{ + return m_texture && (m_texture->size() == size) && (static_cast<BitmapTextureGL*>(m_texture.get())->internalFormat() == internalFormat || internalFormat == GraphicsContext3D::DONT_CARE); +} + +void TextureMapperPlatformLayerBuffer::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& modelViewMatrix, float opacity) +{ + TextureMapperGL& texmapGL = static_cast<TextureMapperGL&>(textureMapper); + + if (m_hasManagedTexture) { + ASSERT(m_texture); + BitmapTextureGL* textureGL = static_cast<BitmapTextureGL*>(m_texture.get()); + texmapGL.drawTexture(textureGL->id(), m_extraFlags, textureGL->size(), targetRect, modelViewMatrix, opacity); + return; + } + + ASSERT(m_textureID); + texmapGL.drawTexture(m_textureID, m_extraFlags, m_size, targetRect, modelViewMatrix, opacity); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h new file mode 100644 index 000000000..2afe5b308 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerBuffer.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. + */ + +#pragma once + +#include "BitmapTextureGL.h" +#include "GraphicsTypes3D.h" +#include "TextureMapperPlatformLayer.h" +#include <wtf/CurrentTime.h> + +#if USE(COORDINATED_GRAPHICS_THREADED) + +namespace WebCore { + +class TextureMapperPlatformLayerBuffer : public TextureMapperPlatformLayer { + WTF_MAKE_NONCOPYABLE(TextureMapperPlatformLayerBuffer); + WTF_MAKE_FAST_ALLOCATED(); +public: + TextureMapperPlatformLayerBuffer(RefPtr<BitmapTexture>&&); + TextureMapperPlatformLayerBuffer(GLuint textureID, const IntSize&, TextureMapperGL::Flags); + + virtual ~TextureMapperPlatformLayerBuffer() = default; + + void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix& modelViewMatrix = TransformationMatrix(), float opacity = 1.0) final; + + bool canReuseWithoutReset(const IntSize&, GC3Dint internalFormat); + BitmapTextureGL& textureGL() { return static_cast<BitmapTextureGL&>(*m_texture); } + + inline void markUsed() { m_timeLastUsed = monotonicallyIncreasingTime(); } + double lastUsedTime() const { return m_timeLastUsed; } + + class UnmanagedBufferDataHolder { + WTF_MAKE_NONCOPYABLE(UnmanagedBufferDataHolder); + WTF_MAKE_FAST_ALLOCATED(); + public: + UnmanagedBufferDataHolder() = default; + virtual ~UnmanagedBufferDataHolder() = default; + }; + + bool hasManagedTexture() const { return m_hasManagedTexture; } + void setUnmanagedBufferDataHolder(std::unique_ptr<UnmanagedBufferDataHolder> holder) { m_unmanagedBufferDataHolder = WTFMove(holder); } + void setExtraFlags(TextureMapperGL::Flags flags) { m_extraFlags = flags; } + +private: + + RefPtr<BitmapTexture> m_texture; + double m_timeLastUsed { 0 }; + + GLuint m_textureID; + IntSize m_size; + TextureMapperGL::Flags m_extraFlags; + bool m_hasManagedTexture; + std::unique_ptr<UnmanagedBufferDataHolder> m_unmanagedBufferDataHolder; +}; + +} // namespace WebCore + +#endif // COORDINATED_GRAPHICS_THREADED diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp new file mode 100644 index 000000000..a3ea24754 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" +#include "TextureMapperPlatformLayerProxy.h" + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include "BitmapTextureGL.h" +#include "TextureMapperGL.h" +#include "TextureMapperLayer.h" +#include "TextureMapperPlatformLayerBuffer.h" + +const double s_releaseUnusedSecondsTolerance = 1; +const double s_releaseUnusedBuffersTimerInterval = 0.5; + +namespace WebCore { + +TextureMapperPlatformLayerProxy::TextureMapperPlatformLayerProxy() + : m_compositor(nullptr) + , m_targetLayer(nullptr) + , m_releaseUnusedBuffersTimer(RunLoop::current(), this, &TextureMapperPlatformLayerProxy::releaseUnusedBuffersTimerFired) +{ +} + +TextureMapperPlatformLayerProxy::~TextureMapperPlatformLayerProxy() +{ + LockHolder locker(m_lock); + if (m_targetLayer) + m_targetLayer->setContentsLayer(nullptr); +} + +void TextureMapperPlatformLayerProxy::activateOnCompositingThread(Compositor* compositor, TextureMapperLayer* targetLayer) +{ +#ifndef NDEBUG + m_compositorThreadID = m_compositorThreadID ? m_compositorThreadID : WTF::currentThread(); +#endif + ASSERT(m_compositorThreadID == WTF::currentThread()); + ASSERT(compositor); + ASSERT(targetLayer); + LockHolder locker(m_lock); + m_compositor = compositor; + m_targetLayer = targetLayer; + if (m_targetLayer && m_currentBuffer) + m_targetLayer->setContentsLayer(m_currentBuffer.get()); + + m_compositorThreadUpdateTimer = std::make_unique<RunLoop::Timer<TextureMapperPlatformLayerProxy>>(RunLoop::current(), this, &TextureMapperPlatformLayerProxy::compositorThreadUpdateTimerFired); +} + +void TextureMapperPlatformLayerProxy::invalidate() +{ + ASSERT(m_compositorThreadID == WTF::currentThread()); + Function<void()> updateFunction; + { + LockHolder locker(m_lock); + m_compositor = nullptr; + m_targetLayer = nullptr; + + m_currentBuffer = nullptr; + m_pendingBuffer = nullptr; + m_releaseUnusedBuffersTimer.stop(); + m_usedBuffers.clear(); + + // Clear the timer and dispatch the update function manually now. + m_compositorThreadUpdateTimer = nullptr; + if (!m_compositorThreadUpdateFunction) + return; + updateFunction = WTFMove(m_compositorThreadUpdateFunction); + } + + updateFunction(); +} + +bool TextureMapperPlatformLayerProxy::isActive() +{ + ASSERT(m_lock.isHeld()); + return !!m_targetLayer && !!m_compositor; +} + +void TextureMapperPlatformLayerProxy::pushNextBuffer(std::unique_ptr<TextureMapperPlatformLayerBuffer> newBuffer) +{ + ASSERT(m_lock.isHeld()); + m_pendingBuffer = WTFMove(newBuffer); + + if (m_compositor) + m_compositor->onNewBufferAvailable(); +} + +std::unique_ptr<TextureMapperPlatformLayerBuffer> TextureMapperPlatformLayerProxy::getAvailableBuffer(const IntSize& size, GC3Dint internalFormat) +{ + ASSERT(m_lock.isHeld()); + std::unique_ptr<TextureMapperPlatformLayerBuffer> availableBuffer; + + auto buffers = WTFMove(m_usedBuffers); + for (auto& buffer : buffers) { + if (!buffer) + continue; + + if (!availableBuffer && buffer->canReuseWithoutReset(size, internalFormat)) { + availableBuffer = WTFMove(buffer); + availableBuffer->markUsed(); + continue; + } + m_usedBuffers.append(WTFMove(buffer)); + } + + if (!m_usedBuffers.isEmpty()) + scheduleReleaseUnusedBuffers(); + return availableBuffer; +} + +void TextureMapperPlatformLayerProxy::scheduleReleaseUnusedBuffers() +{ + if (!m_releaseUnusedBuffersTimer.isActive()) + m_releaseUnusedBuffersTimer.startOneShot(s_releaseUnusedBuffersTimerInterval); +} + +void TextureMapperPlatformLayerProxy::releaseUnusedBuffersTimerFired() +{ + LockHolder locker(m_lock); + if (m_usedBuffers.isEmpty()) + return; + + auto buffers = WTFMove(m_usedBuffers); + double minUsedTime = monotonicallyIncreasingTime() - s_releaseUnusedSecondsTolerance; + + for (auto& buffer : buffers) { + if (buffer && buffer->lastUsedTime() >= minUsedTime) + m_usedBuffers.append(WTFMove(buffer)); + } +} + +void TextureMapperPlatformLayerProxy::swapBuffer() +{ + ASSERT(m_compositorThreadID == WTF::currentThread()); + LockHolder locker(m_lock); + if (!m_targetLayer || !m_pendingBuffer) + return; + + auto prevBuffer = WTFMove(m_currentBuffer); + + m_currentBuffer = WTFMove(m_pendingBuffer); + m_targetLayer->setContentsLayer(m_currentBuffer.get()); + + if (prevBuffer && prevBuffer->hasManagedTexture()) + m_usedBuffers.append(WTFMove(prevBuffer)); +} + +bool TextureMapperPlatformLayerProxy::scheduleUpdateOnCompositorThread(Function<void()>&& updateFunction) +{ + LockHolder locker(m_lock); + if (!m_compositorThreadUpdateTimer) + return false; + + m_compositorThreadUpdateFunction = WTFMove(updateFunction); + m_compositorThreadUpdateTimer->startOneShot(0); + return true; +} + +void TextureMapperPlatformLayerProxy::compositorThreadUpdateTimerFired() +{ + Function<void()> updateFunction; + { + LockHolder locker(m_lock); + if (!m_compositorThreadUpdateFunction) + return; + updateFunction = WTFMove(m_compositorThreadUpdateFunction); + } + + updateFunction(); +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS_THREADED) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h new file mode 100644 index 000000000..b710ab4ce --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayerProxy.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 TextureMapperPlatformLayerProxy_h +#define TextureMapperPlatformLayerProxy_h + +#if USE(COORDINATED_GRAPHICS_THREADED) + +#include "GraphicsTypes3D.h" +#include "TextureMapper.h" +#include "TransformationMatrix.h" +#include <wtf/Condition.h> +#include <wtf/Function.h> +#include <wtf/Lock.h> +#include <wtf/RunLoop.h> +#include <wtf/ThreadSafeRefCounted.h> +#include <wtf/Vector.h> + +#ifndef NDEBUG +#include <wtf/Threading.h> +#endif + +namespace WebCore { + +class TextureMapperLayer; +class TextureMapperPlatformLayerProxy; +class TextureMapperPlatformLayerBuffer; + +class TextureMapperPlatformLayerProxyProvider { +public: + virtual RefPtr<TextureMapperPlatformLayerProxy> proxy() const = 0; + virtual void swapBuffersIfNeeded() = 0; +}; + +class TextureMapperPlatformLayerProxy : public ThreadSafeRefCounted<TextureMapperPlatformLayerProxy> { + WTF_MAKE_FAST_ALLOCATED(); +public: + class Compositor { + public: + virtual void onNewBufferAvailable() = 0; + }; + + TextureMapperPlatformLayerProxy(); + virtual ~TextureMapperPlatformLayerProxy(); + + // To avoid multiple lock/release situation to update a single frame, + // the implementation of TextureMapperPlatformLayerProxyProvider should + // aquire / release the lock explicitly to use below methods. + Lock& lock() { return m_lock; } + std::unique_ptr<TextureMapperPlatformLayerBuffer> getAvailableBuffer(const IntSize&, GC3Dint internalFormat); + void pushNextBuffer(std::unique_ptr<TextureMapperPlatformLayerBuffer>); + bool isActive(); + + void activateOnCompositingThread(Compositor*, TextureMapperLayer*); + void invalidate(); + + void swapBuffer(); + + bool scheduleUpdateOnCompositorThread(Function<void()>&&); + +private: + void scheduleReleaseUnusedBuffers(); + void releaseUnusedBuffersTimerFired(); + + Compositor* m_compositor; + TextureMapperLayer* m_targetLayer; + + std::unique_ptr<TextureMapperPlatformLayerBuffer> m_currentBuffer; + std::unique_ptr<TextureMapperPlatformLayerBuffer> m_pendingBuffer; + + Lock m_lock; + + Vector<std::unique_ptr<TextureMapperPlatformLayerBuffer>> m_usedBuffers; + + RunLoop::Timer<TextureMapperPlatformLayerProxy> m_releaseUnusedBuffersTimer; +#ifndef NDEBUG + ThreadIdentifier m_compositorThreadID { 0 }; +#endif + + void compositorThreadUpdateTimerFired(); + std::unique_ptr<RunLoop::Timer<TextureMapperPlatformLayerProxy>> m_compositorThreadUpdateTimer; + Function<void()> m_compositorThreadUpdateFunction; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS_THREADED) + +#endif // TextureMapperPlatformLayerProxy_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp index 5c0a76db6..b0c371b99 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.cpp @@ -22,19 +22,12 @@ #include "config.h" #include "TextureMapperShaderProgram.h" -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) -#include "LengthFunctions.h" +#if USE(TEXTURE_MAPPER_GL) + #include "Logging.h" #include "TextureMapperGL.h" - #include <wtf/text/StringBuilder.h> -#if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS)) -#undef NO_ERROR -#endif - -#define STRINGIFY(...) #__VA_ARGS__ - namespace WebCore { static inline bool compositingLogEnabled() @@ -46,85 +39,21 @@ static inline bool compositingLogEnabled() #endif } -TextureMapperShaderProgram::TextureMapperShaderProgram(PassRefPtr<GraphicsContext3D> context, const String& vertex, const String& fragment) - : m_context(context) -{ - m_vertexShader = m_context->createShader(GraphicsContext3D::VERTEX_SHADER); - m_fragmentShader = m_context->createShader(GraphicsContext3D::FRAGMENT_SHADER); - m_context->shaderSource(m_vertexShader, vertex); - m_context->shaderSource(m_fragmentShader, fragment); - m_id = m_context->createProgram(); - m_context->compileShader(m_vertexShader); - m_context->compileShader(m_fragmentShader); - m_context->attachShader(m_id, m_vertexShader); - m_context->attachShader(m_id, m_fragmentShader); - m_context->linkProgram(m_id); - - if (!compositingLogEnabled()) - return; - - if (m_context->getError() == GraphicsContext3D::NO_ERROR) - return; - - String log = m_context->getShaderInfoLog(m_vertexShader); - LOG(Compositing, "Vertex shader log: %s\n", log.utf8().data()); - log = m_context->getShaderInfoLog(m_fragmentShader); - LOG(Compositing, "Fragment shader log: %s\n", log.utf8().data()); - log = m_context->getProgramInfoLog(m_id); - LOG(Compositing, "Program log: %s\n", log.utf8().data()); -} - -void TextureMapperShaderProgram::setMatrix(GC3Duint location, const TransformationMatrix& matrix) -{ - GC3Dfloat matrixAsFloats[] = { - GC3Dfloat(matrix.m11()), GC3Dfloat(matrix.m12()), GC3Dfloat(matrix.m13()), GC3Dfloat(matrix.m14()), - GC3Dfloat(matrix.m21()), GC3Dfloat(matrix.m22()), GC3Dfloat(matrix.m23()), GC3Dfloat(matrix.m24()), - GC3Dfloat(matrix.m31()), GC3Dfloat(matrix.m32()), GC3Dfloat(matrix.m33()), GC3Dfloat(matrix.m34()), - GC3Dfloat(matrix.m41()), GC3Dfloat(matrix.m42()), GC3Dfloat(matrix.m43()), GC3Dfloat(matrix.m44()) - }; - - m_context->uniformMatrix4fv(location, 1, false, matrixAsFloats); -} - -GC3Duint TextureMapperShaderProgram::getLocation(const AtomicString& name, VariableType type) -{ - HashMap<AtomicString, GC3Duint>::iterator it = m_variables.find(name); - if (it != m_variables.end()) - return it->value; - - GC3Duint location = 0; - switch (type) { - case UniformVariable: - location = m_context->getUniformLocation(m_id, name); - break; - case AttribVariable: - location = m_context->getAttribLocation(m_id, name); - break; - default: - ASSERT_NOT_REACHED(); - break; - } - - m_variables.add(name, location); - return location; -} +#define STRINGIFY(...) #__VA_ARGS__ -TextureMapperShaderProgram::~TextureMapperShaderProgram() -{ - Platform3DObject programID = m_id; - if (!programID) - return; +#define GLSL_DIRECTIVE(...) "#"#__VA_ARGS__"\n" - m_context->detachShader(programID, m_vertexShader); - m_context->deleteShader(m_vertexShader); - m_context->detachShader(programID, m_fragmentShader); - m_context->deleteShader(m_fragmentShader); - m_context->deleteProgram(programID); -} +#define TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE \ + GLSL_DIRECTIVE(ifdef GL_FRAGMENT_PRECISION_HIGH) \ + GLSL_DIRECTIVE(define TextureSpaceMatrixPrecision highp) \ + GLSL_DIRECTIVE(else) \ + GLSL_DIRECTIVE(define TextureSpaceMatrixPrecision mediump) \ + GLSL_DIRECTIVE(endif) -#define GLSL_DIRECTIVE(...) "#"#__VA_ARGS__"\n" static const char* vertexTemplate = + TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE STRINGIFY( + precision TextureSpaceMatrixPrecision float; attribute vec4 a_vertex; uniform mat4 u_modelViewMatrix; uniform mat4 u_projectionMatrix; @@ -211,7 +140,10 @@ static const char* fragmentTemplate = RECT_TEXTURE_DIRECTIVE ANTIALIASING_TEX_COORD_DIRECTIVE BLUR_CONSTANTS + TEXTURE_SPACE_MATRIX_PRECISION_DIRECTIVE STRINGIFY( + precision TextureSpaceMatrixPrecision float; + uniform mat4 u_textureSpaceMatrix; precision mediump float; uniform SamplerType s_sampler; uniform sampler2D s_contentTexture; @@ -224,10 +156,10 @@ static const char* fragmentTemplate = uniform vec2 u_shadowOffset; uniform vec4 u_color; uniform float u_gaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH]; - uniform mat4 u_textureSpaceMatrix; void noop(inout vec4 dummyParameter) { } void noop(inout vec4 dummyParameter, vec2 texCoord) { } + void noop(inout vec2 dummyParameter) { } float antialias() { return smoothstep(0., 1., v_antialias); } @@ -239,6 +171,8 @@ static const char* fragmentTemplate = vec2 vertexTransformTexCoord() { return v_transformedTexCoord; } + void applyManualRepeat(inout vec2 pos) { pos = fract(pos); } + void applyTexture(inout vec4 color, vec2 texCoord) { color = SamplerFunction(s_sampler, texCoord); } void applyOpacity(inout vec4 color) { color *= u_opacity; } void applyAntialiasing(inout vec4 color) { color *= antialias(); } @@ -350,6 +284,7 @@ static const char* fragmentTemplate = { vec4 color = vec4(1., 1., 1., 1.); vec2 texCoord = transformTexCoord(); + applyManualRepeatIfNeeded(texCoord); applyTextureIfNeeded(color, texCoord); applySolidColorIfNeeded(color); applyAntialiasingIfNeeded(color); @@ -369,13 +304,13 @@ static const char* fragmentTemplate = } ); -PassRefPtr<TextureMapperShaderProgram> TextureMapperShaderProgram::create(PassRefPtr<GraphicsContext3D> context, TextureMapperShaderProgram::Options options) +Ref<TextureMapperShaderProgram> TextureMapperShaderProgram::create(Ref<GraphicsContext3D>&& context, TextureMapperShaderProgram::Options options) { - StringBuilder shaderBuilder; #define SET_APPLIER_FROM_OPTIONS(Applier) \ - shaderBuilder.append(\ + optionsApplierBuilder.append(\ (options & TextureMapperShaderProgram::Applier) ? ENABLE_APPLIER(Applier) : DISABLE_APPLIER(Applier)) + StringBuilder optionsApplierBuilder; SET_APPLIER_FROM_OPTIONS(Texture); SET_APPLIER_FROM_OPTIONS(Rect); SET_APPLIER_FROM_OPTIONS(SolidColor); @@ -392,16 +327,84 @@ PassRefPtr<TextureMapperShaderProgram> TextureMapperShaderProgram::create(PassRe SET_APPLIER_FROM_OPTIONS(BlurFilter); SET_APPLIER_FROM_OPTIONS(AlphaBlur); SET_APPLIER_FROM_OPTIONS(ContentTexture); - StringBuilder vertexBuilder; - vertexBuilder.append(shaderBuilder.toString()); - vertexBuilder.append(vertexTemplate); - shaderBuilder.append(fragmentTemplate); + SET_APPLIER_FROM_OPTIONS(ManualRepeat); + + StringBuilder vertexShaderBuilder; + vertexShaderBuilder.append(optionsApplierBuilder.toString()); + vertexShaderBuilder.append(vertexTemplate); + + StringBuilder fragmentShaderBuilder; + fragmentShaderBuilder.append(optionsApplierBuilder.toString()); + fragmentShaderBuilder.append(fragmentTemplate); + + return adoptRef(*new TextureMapperShaderProgram(WTFMove(context), vertexShaderBuilder.toString(), fragmentShaderBuilder.toString())); +} + +TextureMapperShaderProgram::TextureMapperShaderProgram(Ref<GraphicsContext3D>&& context, const String& vertex, const String& fragment) + : m_context(WTFMove(context)) +{ + m_vertexShader = m_context->createShader(GraphicsContext3D::VERTEX_SHADER); + m_context->shaderSource(m_vertexShader, vertex); + + m_fragmentShader = m_context->createShader(GraphicsContext3D::FRAGMENT_SHADER); + m_context->shaderSource(m_fragmentShader, fragment); + + m_id = m_context->createProgram(); + m_context->compileShader(m_vertexShader); + m_context->compileShader(m_fragmentShader); + m_context->attachShader(m_id, m_vertexShader); + m_context->attachShader(m_id, m_fragmentShader); + m_context->linkProgram(m_id); + + if (!compositingLogEnabled()) + return; + + if (m_context->getError() == GraphicsContext3D::NO_ERROR) + return; - String vertexSource = vertexBuilder.toString(); - String fragmentSource = shaderBuilder.toString(); + String log = m_context->getShaderInfoLog(m_vertexShader); + LOG(Compositing, "Vertex shader log: %s\n", log.utf8().data()); + log = m_context->getShaderInfoLog(m_fragmentShader); + LOG(Compositing, "Fragment shader log: %s\n", log.utf8().data()); + log = m_context->getProgramInfoLog(m_id); + LOG(Compositing, "Program log: %s\n", log.utf8().data()); +} + +TextureMapperShaderProgram::~TextureMapperShaderProgram() +{ + if (!m_id) + return; - return adoptRef(new TextureMapperShaderProgram(context, vertexSource, fragmentSource)); + m_context->detachShader(m_id, m_vertexShader); + m_context->deleteShader(m_vertexShader); + m_context->detachShader(m_id, m_fragmentShader); + m_context->deleteShader(m_fragmentShader); + m_context->deleteProgram(m_id); } +void TextureMapperShaderProgram::setMatrix(GC3Duint location, const TransformationMatrix& matrix) +{ + TransformationMatrix::FloatMatrix4 floatMatrix; + matrix.toColumnMajorFloatArray(floatMatrix); + m_context->uniformMatrix4fv(location, 1, false, floatMatrix); } -#endif + +GC3Duint TextureMapperShaderProgram::getLocation(const AtomicString& name, VariableType type) +{ + auto addResult = m_variables.ensure(name, + [this, &name, type] { + switch (type) { + case UniformVariable: + return m_context->getUniformLocation(m_id, name); + case AttribVariable: + return m_context->getAttribLocation(m_id, name); + } + ASSERT_NOT_REACHED(); + return 0; + }); + return addResult.iterator->value; +} + +} // namespace WebCore + +#endif // USE(TEXTURE_MAPPER_GL) diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h index 3345fc9fe..541a42b27 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperShaderProgram.h @@ -21,16 +21,23 @@ #ifndef TextureMapperShaderProgram_h #define TextureMapperShaderProgram_h -#if USE(TEXTURE_MAPPER) +#if USE(TEXTURE_MAPPER_GL) + #include "GraphicsContext3D.h" #include "TransformationMatrix.h" #include <wtf/HashMap.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/Ref.h> #include <wtf/text/AtomicStringHash.h> namespace WebCore { -#define TEXMAP_DECLARE_VARIABLE(Accessor, Name, Type) GC3Duint Accessor##Location() { static const AtomicString name(Name); return getLocation(name, Type); } + +#define TEXMAP_DECLARE_VARIABLE(Accessor, Name, Type) \ + GC3Duint Accessor##Location() { \ + static NeverDestroyed<const AtomicString> name(Name, AtomicString::ConstructFromLiteral); \ + return getLocation(name.get(), Type); \ + } + #define TEXMAP_DECLARE_UNIFORM(Accessor) TEXMAP_DECLARE_VARIABLE(Accessor, "u_"#Accessor, UniformVariable) #define TEXMAP_DECLARE_ATTRIBUTE(Accessor) TEXMAP_DECLARE_VARIABLE(Accessor, "a_"#Accessor, AttribVariable) #define TEXMAP_DECLARE_SAMPLER(Accessor) TEXMAP_DECLARE_VARIABLE(Accessor, "s_"#Accessor, UniformVariable) @@ -53,15 +60,17 @@ public: OpacityFilter = 1L << 13, BlurFilter = 1L << 14, AlphaBlur = 1L << 15, - ContentTexture = 1L << 16 + ContentTexture = 1L << 16, + ManualRepeat = 1L << 17 }; typedef unsigned Options; - static PassRefPtr<TextureMapperShaderProgram> create(PassRefPtr<GraphicsContext3D>, Options); + static Ref<TextureMapperShaderProgram> create(Ref<GraphicsContext3D>&&, Options); virtual ~TextureMapperShaderProgram(); + Platform3DObject programID() const { return m_id; } - GraphicsContext3D* context() { return m_context.get(); } + GraphicsContext3D& context() { return m_context; } TEXMAP_DECLARE_ATTRIBUTE(vertex) @@ -74,30 +83,29 @@ public: TEXMAP_DECLARE_SAMPLER(sampler) TEXMAP_DECLARE_SAMPLER(mask) -#if ENABLE(CSS_FILTERS) TEXMAP_DECLARE_UNIFORM(filterAmount) TEXMAP_DECLARE_UNIFORM(gaussianKernel) TEXMAP_DECLARE_UNIFORM(blurRadius) TEXMAP_DECLARE_UNIFORM(shadowOffset) TEXMAP_DECLARE_SAMPLER(contentTexture) -#endif void setMatrix(GC3Duint, const TransformationMatrix&); private: - TextureMapperShaderProgram(PassRefPtr<GraphicsContext3D>, const String& vertexShaderSource, const String& fragmentShaderSource); + TextureMapperShaderProgram(Ref<GraphicsContext3D>&&, const String& vertexShaderSource, const String& fragmentShaderSource); + Platform3DObject m_vertexShader; Platform3DObject m_fragmentShader; enum VariableType { UniformVariable, AttribVariable }; GC3Duint getLocation(const AtomicString&, VariableType); - RefPtr<GraphicsContext3D> m_context; + Ref<GraphicsContext3D> m_context; Platform3DObject m_id; HashMap<AtomicString, GC3Duint> m_variables; }; } -#endif +#endif // USE(TEXTURE_MAPPER_GL) #endif // TextureMapperShaderProgram_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.cpp deleted file mode 100644 index 8d38776e9..000000000 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#if USE(ACCELERATED_COMPOSITING) && USE(GRAPHICS_SURFACE) -#include "TextureMapperSurfaceBackingStore.h" - -#include "GraphicsSurface.h" - -namespace WebCore { - -void TextureMapperSurfaceBackingStore::setGraphicsSurface(PassRefPtr<GraphicsSurface> surface) -{ - m_graphicsSurface = surface; -} - -void TextureMapperSurfaceBackingStore::swapBuffersIfNeeded(uint32_t) -{ - if (m_graphicsSurface) - m_graphicsSurface->swapBuffers(); -} - -PassRefPtr<BitmapTexture> TextureMapperSurfaceBackingStore::texture() const -{ - // FIXME: Instead of just returning an empty texture, we should wrap the texture contents into a BitmapTexture. - RefPtr<BitmapTexture> emptyTexture; - return emptyTexture; -} - -void TextureMapperSurfaceBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) -{ - if (m_graphicsSurface) - m_graphicsSurface->paintToTextureMapper(textureMapper, targetRect, transform, opacity); -} - -} // namespace WebCore -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.h deleted file mode 100644 index 793c61dc3..000000000 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperSurfaceBackingStore.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -#ifndef TextureMapperSurfaceBackingStore_h -#define TextureMapperSurfaceBackingStore_h - -#if USE(ACCELERATED_COMPOSITING) && USE(GRAPHICS_SURFACE) - -#include "GraphicsSurface.h" -#include "TextureMapperBackingStore.h" -#include <wtf/RefPtr.h> - -namespace WebCore { - -class TextureMapper; -class FloatRect; - -class TextureMapperSurfaceBackingStore : public TextureMapperBackingStore { -public: - static PassRefPtr<TextureMapperSurfaceBackingStore> create() { return adoptRef(new TextureMapperSurfaceBackingStore); } - void setGraphicsSurface(PassRefPtr<GraphicsSurface>); - void swapBuffersIfNeeded(uint32_t frontBuffer); - virtual PassRefPtr<BitmapTexture> texture() const; - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float); - virtual ~TextureMapperSurfaceBackingStore() { } - -private: - TextureMapperSurfaceBackingStore() - : TextureMapperBackingStore() - { } - - RefPtr<GraphicsSurface> m_graphicsSurface; -}; - -} - -#endif - -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp index 2ea7fb6ed..39365673e 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.cpp @@ -18,18 +18,16 @@ */ #include "config.h" -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "TextureMapperTile.h" #include "Image.h" #include "TextureMapper.h" -#include <wtf/RefPtr.h> namespace WebCore { class GraphicsLayer; -void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* image, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +void TextureMapperTile::updateContents(TextureMapper& textureMapper, Image* image, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) { IntRect targetRect = enclosingIntRect(m_rect); targetRect.intersect(dirtyRect); @@ -43,14 +41,14 @@ void TextureMapperTile::updateContents(TextureMapper* textureMapper, Image* imag // Normalize targetRect to the texture's coordinates. targetRect.move(-m_rect.x(), -m_rect.y()); if (!m_texture) { - m_texture = textureMapper->createTexture(); + m_texture = textureMapper.createTexture(); m_texture->reset(targetRect.size(), image->currentFrameKnownToBeOpaque() ? 0 : BitmapTexture::SupportsAlpha); } m_texture->updateContents(image, targetRect, sourceOffset, updateContentsFlag); } -void TextureMapperTile::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +void TextureMapperTile::updateContents(TextureMapper& textureMapper, GraphicsLayer* sourceLayer, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag, float scale) { IntRect targetRect = enclosingIntRect(m_rect); targetRect.intersect(dirtyRect); @@ -62,18 +60,17 @@ void TextureMapperTile::updateContents(TextureMapper* textureMapper, GraphicsLay targetRect.move(-m_rect.x(), -m_rect.y()); if (!m_texture) { - m_texture = textureMapper->createTexture(); + m_texture = textureMapper.createTexture(); m_texture->reset(targetRect.size(), BitmapTexture::SupportsAlpha); } - m_texture->updateContents(textureMapper, sourceLayer, targetRect, sourceOffset, updateContentsFlag); + m_texture->updateContents(textureMapper, sourceLayer, targetRect, sourceOffset, updateContentsFlag, scale); } -void TextureMapperTile::paint(TextureMapper* textureMapper, const TransformationMatrix& transform, float opacity, const unsigned exposedEdges) +void TextureMapperTile::paint(TextureMapper& textureMapper, const TransformationMatrix& transform, float opacity, const unsigned exposedEdges) { if (texture().get()) - textureMapper->drawTexture(*texture().get(), rect(), transform, opacity, exposedEdges); + textureMapper.drawTexture(*texture().get(), rect(), transform, opacity, exposedEdges); } } // namespace WebCore -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h index ee6809f20..6aebd3139 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTile.h @@ -20,8 +20,6 @@ #ifndef TextureMapperTile_h #define TextureMapperTile_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - #include "FloatRect.h" #include "Image.h" #include "TextureMapper.h" @@ -34,14 +32,14 @@ class GraphicsLayer; class TextureMapperTile { public: - inline PassRefPtr<BitmapTexture> texture() const { return m_texture; } + inline RefPtr<BitmapTexture> texture() const { return m_texture; } inline FloatRect rect() const { return m_rect; } inline void setTexture(BitmapTexture* texture) { m_texture = texture; } inline void setRect(const FloatRect& rect) { m_rect = rect; } - void updateContents(TextureMapper*, Image*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); - void updateContents(TextureMapper*, GraphicsLayer*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); - virtual void paint(TextureMapper*, const TransformationMatrix&, float, const unsigned exposedEdges); + void updateContents(TextureMapper&, Image*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData); + void updateContents(TextureMapper&, GraphicsLayer*, const IntRect&, BitmapTexture::UpdateContentsFlag UpdateCanModifyOriginalImageData, float scale = 1); + virtual void paint(TextureMapper&, const TransformationMatrix&, float, const unsigned exposedEdges); virtual ~TextureMapperTile() { } explicit TextureMapperTile(const FloatRect& rect) @@ -55,6 +53,5 @@ private: }; } -#endif #endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp index ef564023d..6833ac6b5 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.cpp @@ -19,27 +19,26 @@ #include "config.h" -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) #include "TextureMapperTiledBackingStore.h" #include "ImageBuffer.h" +#include "ImageObserver.h" #include "TextureMapper.h" namespace WebCore { class GraphicsLayer; -TextureMapperTiledBackingStore::TextureMapperTiledBackingStore() -{ -} - -void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapper* textureMapper) +void TextureMapperTiledBackingStore::updateContentsFromImageIfNeeded(TextureMapper& textureMapper) { if (!m_image) return; - updateContents(textureMapper, m_image.get(), m_image->size(), m_image->rect(), BitmapTexture::UpdateCannotModifyOriginalImageData); - m_image.clear(); + updateContents(textureMapper, m_image.get(), m_image->size(), enclosingIntRect(m_image->rect()), BitmapTexture::UpdateCannotModifyOriginalImageData); + + if (m_image->imageObserver()) + m_image->imageObserver()->didDraw(m_image.get()); + m_image = nullptr; } TransformationMatrix TextureMapperTiledBackingStore::adjustedTransformForRect(const FloatRect& targetRect) @@ -47,34 +46,48 @@ TransformationMatrix TextureMapperTiledBackingStore::adjustedTransformForRect(co return TransformationMatrix::rectToRect(rect(), targetRect); } -void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper* textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) +void TextureMapperTiledBackingStore::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& transform, float opacity) { updateContentsFromImageIfNeeded(textureMapper); TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); - for (size_t i = 0; i < m_tiles.size(); ++i) - m_tiles[i].paint(textureMapper, adjustedTransform, opacity, calculateExposedTileEdges(rect(), m_tiles[i].rect())); + for (auto& tile : m_tiles) + tile.paint(textureMapper, adjustedTransform, opacity, calculateExposedTileEdges(rect(), tile.rect())); } -void TextureMapperTiledBackingStore::drawBorder(TextureMapper* textureMapper, const Color& borderColor, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) +void TextureMapperTiledBackingStore::drawBorder(TextureMapper& textureMapper, const Color& borderColor, float borderWidth, const FloatRect& targetRect, const TransformationMatrix& transform) { TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); - for (size_t i = 0; i < m_tiles.size(); ++i) - textureMapper->drawBorder(borderColor, borderWidth, m_tiles[i].rect(), adjustedTransform); + for (auto& tile : m_tiles) + textureMapper.drawBorder(borderColor, borderWidth, tile.rect(), adjustedTransform); } -void TextureMapperTiledBackingStore::drawRepaintCounter(TextureMapper* textureMapper, int repaintCount, const Color& borderColor, const FloatRect& targetRect, const TransformationMatrix& transform) +void TextureMapperTiledBackingStore::drawRepaintCounter(TextureMapper& textureMapper, int repaintCount, const Color& borderColor, const FloatRect& targetRect, const TransformationMatrix& transform) { TransformationMatrix adjustedTransform = transform * adjustedTransformForRect(targetRect); - for (size_t i = 0; i < m_tiles.size(); ++i) - textureMapper->drawNumber(repaintCount, borderColor, m_tiles[i].rect().location(), adjustedTransform); + for (auto& tile : m_tiles) + textureMapper.drawNumber(repaintCount, borderColor, tile.rect().location(), adjustedTransform); +} + +void TextureMapperTiledBackingStore::updateContentsScale(float scale) +{ + if (m_contentsScale == scale) + return; + + m_isScaleDirty = true; + m_contentsScale = scale; } void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSize& size, const IntSize& tileSize, bool hasAlpha) { - if (size == m_size) + if (size == m_size && !m_isScaleDirty) return; m_size = size; + m_isScaleDirty = false; + + FloatSize scaledSize(m_size); + if (!m_image) + scaledSize.scale(m_contentsScale); Vector<FloatRect> tileRectsToAdd; Vector<int> tileIndicesToRemove; @@ -82,8 +95,8 @@ void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSiz // This method recycles tiles. We check which tiles we need to add, which to remove, and use as many // removable tiles as replacement for new tiles when possible. - for (float y = 0; y < m_size.height(); y += tileSize.height()) { - for (float x = 0; x < m_size.width(); x += tileSize.width()) { + for (float y = 0; y < scaledSize.height(); y += tileSize.height()) { + for (float x = 0; x < scaledSize.width(); x += tileSize.width()) { FloatRect tileRect(x, y, tileSize.width(), tileSize.height()); tileRect.intersect(rect()); tileRectsToAdd.append(tileRect); @@ -112,51 +125,52 @@ void TextureMapperTiledBackingStore::createOrDestroyTilesIfNeeded(const FloatSiz } // Recycle removable tiles to be used for newly requested tiles. - for (size_t i = 0; i < tileRectsToAdd.size(); ++i) { + for (auto& rect : tileRectsToAdd) { if (!tileIndicesToRemove.isEmpty()) { // We recycle an existing tile for usage with a new tile rect. TextureMapperTile& tile = m_tiles[tileIndicesToRemove.last()]; tileIndicesToRemove.removeLast(); - tile.setRect(tileRectsToAdd[i]); + tile.setRect(rect); if (tile.texture()) tile.texture()->reset(enclosingIntRect(tile.rect()).size(), hasAlpha ? BitmapTexture::SupportsAlpha : 0); continue; } - m_tiles.append(TextureMapperTile(tileRectsToAdd[i])); + m_tiles.append(TextureMapperTile(rect)); } // Remove unnecessary tiles, if they weren't recycled. // We use a threshold to make sure we don't create/destroy tiles too eagerly. - for (size_t i = 0; i < tileIndicesToRemove.size() && m_tiles.size() > TileEraseThreshold; ++i) - m_tiles.remove(tileIndicesToRemove[i]); + for (auto& index : tileIndicesToRemove) { + if (m_tiles.size() <= TileEraseThreshold) + break; + m_tiles.remove(index); + } } -void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +void TextureMapperTiledBackingStore::updateContents(TextureMapper& textureMapper, Image* image, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) { - createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), !image->currentFrameKnownToBeOpaque()); - for (size_t i = 0; i < m_tiles.size(); ++i) - m_tiles[i].updateContents(textureMapper, image, dirtyRect, updateContentsFlag); + createOrDestroyTilesIfNeeded(totalSize, textureMapper.maxTextureSize(), !image->currentFrameKnownToBeOpaque()); + for (auto& tile : m_tiles) + tile.updateContents(textureMapper, image, dirtyRect, updateContentsFlag); } -void TextureMapperTiledBackingStore::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) +void TextureMapperTiledBackingStore::updateContents(TextureMapper& textureMapper, GraphicsLayer* sourceLayer, const FloatSize& totalSize, const IntRect& dirtyRect, BitmapTexture::UpdateContentsFlag updateContentsFlag) { - createOrDestroyTilesIfNeeded(totalSize, textureMapper->maxTextureSize(), true); - for (size_t i = 0; i < m_tiles.size(); ++i) - m_tiles[i].updateContents(textureMapper, sourceLayer, dirtyRect, updateContentsFlag); + createOrDestroyTilesIfNeeded(totalSize, textureMapper.maxTextureSize(), true); + for (auto& tile : m_tiles) + tile.updateContents(textureMapper, sourceLayer, dirtyRect, updateContentsFlag, m_contentsScale); } -PassRefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const +RefPtr<BitmapTexture> TextureMapperTiledBackingStore::texture() const { - for (size_t i = 0; i < m_tiles.size(); ++i) { - RefPtr<BitmapTexture> texture = m_tiles[i].texture(); - if (texture) + for (const auto& tile : m_tiles) { + if (auto texture = tile.texture()) return texture; } - return PassRefPtr<BitmapTexture>(); + return nullptr; } } // namespace WebCore -#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h index 38161c475..8514a4f73 100644 --- a/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperTiledBackingStore.h @@ -20,8 +20,6 @@ #ifndef TextureMapperTiledBackingStore_h #define TextureMapperTiledBackingStore_h -#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) - #include "FloatRect.h" #include "Image.h" #include "TextureMapperBackingStore.h" @@ -37,28 +35,37 @@ public: static PassRefPtr<TextureMapperTiledBackingStore> create() { return adoptRef(new TextureMapperTiledBackingStore); } virtual ~TextureMapperTiledBackingStore() { } - virtual PassRefPtr<BitmapTexture> texture() const override; - virtual void paintToTextureMapper(TextureMapper*, const FloatRect&, const TransformationMatrix&, float) override; - virtual void drawBorder(TextureMapper*, const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) override; - virtual void drawRepaintCounter(TextureMapper*, int repaintCount, const Color&, const FloatRect&, const TransformationMatrix&) override; - void updateContents(TextureMapper*, Image*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); - void updateContents(TextureMapper*, GraphicsLayer*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); + RefPtr<BitmapTexture> texture() const override; + void paintToTextureMapper(TextureMapper&, const FloatRect&, const TransformationMatrix&, float) override; + void drawBorder(TextureMapper&, const Color&, float borderWidth, const FloatRect&, const TransformationMatrix&) override; + void drawRepaintCounter(TextureMapper&, int repaintCount, const Color&, const FloatRect&, const TransformationMatrix&) override; + + void updateContentsScale(float); + void updateContents(TextureMapper&, Image*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); + void updateContents(TextureMapper&, GraphicsLayer*, const FloatSize&, const IntRect&, BitmapTexture::UpdateContentsFlag); void setContentsToImage(Image* image) { m_image = image; } private: - TextureMapperTiledBackingStore(); + TextureMapperTiledBackingStore() { } + void createOrDestroyTilesIfNeeded(const FloatSize& backingStoreSize, const IntSize& tileSize, bool hasAlpha); - void updateContentsFromImageIfNeeded(TextureMapper*); + void updateContentsFromImageIfNeeded(TextureMapper&); TransformationMatrix adjustedTransformForRect(const FloatRect&); - inline FloatRect rect() const { return FloatRect(FloatPoint::zero(), m_size); } + inline FloatRect rect() const + { + FloatRect rect(FloatPoint::zero(), m_size); + rect.scale(m_contentsScale); + return rect; + } Vector<TextureMapperTile> m_tiles; FloatSize m_size; RefPtr<Image> m_image; + float m_contentsScale { 1 }; + bool m_isScaleDirty { false }; }; } // namespace WebCore -#endif #endif diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp new file mode 100644 index 000000000..8da58b2ce --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.cpp @@ -0,0 +1,1182 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2010 Apple Inc. All rights reserved. + Copyright (C) 2012 Company 100, Inc. + Copyright (C) 2012 Intel Corporation. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "CoordinatedGraphicsLayer.h" + +#if USE(COORDINATED_GRAPHICS) + +#include "FloatQuad.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerFactory.h" +#include "ScrollableArea.h" +#include <wtf/CurrentTime.h> +#ifndef NDEBUG +#include <wtf/SetForScope.h> +#endif +#include <wtf/text/CString.h> + +namespace WebCore { + +std::unique_ptr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient& client, Type layerType) +{ + if (!factory) + return std::make_unique<CoordinatedGraphicsLayer>(layerType, client); + + return factory->createGraphicsLayer(layerType, client); +} + +static CoordinatedLayerID toCoordinatedLayerID(GraphicsLayer* layer) +{ + return is<CoordinatedGraphicsLayer>(layer) ? downcast<CoordinatedGraphicsLayer>(*layer).id() : 0; +} + +void CoordinatedGraphicsLayer::notifyFlushRequired() +{ + if (!m_coordinator) + return; + + if (m_coordinator->isFlushingLayerChanges()) + return; + + client().notifyFlushRequired(this); +} + +void CoordinatedGraphicsLayer::didChangeLayerState() +{ + m_shouldSyncLayerState = true; + notifyFlushRequired(); +} + +void CoordinatedGraphicsLayer::didChangeAnimations() +{ + m_shouldSyncAnimations = true; + notifyFlushRequired(); +} + +void CoordinatedGraphicsLayer::didChangeChildren() +{ + m_shouldSyncChildren = true; + notifyFlushRequired(); +} + +void CoordinatedGraphicsLayer::didChangeFilters() +{ + m_shouldSyncFilters = true; + notifyFlushRequired(); +} + +void CoordinatedGraphicsLayer::didChangeImageBacking() +{ + m_shouldSyncImageBacking = true; + notifyFlushRequired(); +} + +void CoordinatedGraphicsLayer::setShouldUpdateVisibleRect() +{ + m_shouldUpdateVisibleRect = true; + for (auto& child : children()) + downcast<CoordinatedGraphicsLayer>(*child).setShouldUpdateVisibleRect(); + if (replicaLayer()) + downcast<CoordinatedGraphicsLayer>(*replicaLayer()).setShouldUpdateVisibleRect(); +} + +void CoordinatedGraphicsLayer::didChangeGeometry() +{ + didChangeLayerState(); + setShouldUpdateVisibleRect(); +} + +CoordinatedGraphicsLayer::CoordinatedGraphicsLayer(Type layerType, GraphicsLayerClient& client) + : GraphicsLayer(layerType, client) +#ifndef NDEBUG + , m_isPurging(false) +#endif + , m_shouldUpdateVisibleRect(true) + , m_shouldSyncLayerState(true) + , m_shouldSyncChildren(true) + , m_shouldSyncFilters(true) + , m_shouldSyncImageBacking(true) + , m_shouldSyncAnimations(true) + , m_fixedToViewport(false) + , m_movingVisibleRect(false) + , m_pendingContentsScaleAdjustment(false) + , m_pendingVisibleRectAdjustment(false) +#if USE(COORDINATED_GRAPHICS_THREADED) + , m_shouldSyncPlatformLayer(false) + , m_shouldUpdatePlatformLayer(false) +#endif + , m_coordinator(0) + , m_compositedNativeImagePtr(0) + , m_platformLayer(0) + , m_animationStartedTimer(*this, &CoordinatedGraphicsLayer::animationStartedTimerFired) + , m_scrollableArea(0) +{ + static CoordinatedLayerID nextLayerID = 1; + m_id = nextLayerID++; +} + +CoordinatedGraphicsLayer::~CoordinatedGraphicsLayer() +{ + if (m_coordinator) { + purgeBackingStores(); + m_coordinator->detachLayer(this); + } + ASSERT(!m_coordinatedImageBacking); + ASSERT(!m_mainBackingStore); + willBeDestroyed(); +} + +bool CoordinatedGraphicsLayer::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool ok = GraphicsLayer::setChildren(children); + if (!ok) + return false; + didChangeChildren(); + return true; +} + +void CoordinatedGraphicsLayer::addChild(GraphicsLayer* layer) +{ + GraphicsLayer::addChild(layer); + didChangeChildren(); +} + +void CoordinatedGraphicsLayer::addChildAtIndex(GraphicsLayer* layer, int index) +{ + GraphicsLayer::addChildAtIndex(layer, index); + didChangeChildren(); +} + +void CoordinatedGraphicsLayer::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildAbove(layer, sibling); + didChangeChildren(); +} + +void CoordinatedGraphicsLayer::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(layer, sibling); + didChangeChildren(); +} + +bool CoordinatedGraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + bool ok = GraphicsLayer::replaceChild(oldChild, newChild); + if (!ok) + return false; + didChangeChildren(); + return true; +} + +void CoordinatedGraphicsLayer::removeFromParent() +{ + if (CoordinatedGraphicsLayer* parentLayer = downcast<CoordinatedGraphicsLayer>(parent())) + parentLayer->didChangeChildren(); + GraphicsLayer::removeFromParent(); +} + +void CoordinatedGraphicsLayer::setPosition(const FloatPoint& p) +{ + if (position() == p) + return; + + GraphicsLayer::setPosition(p); + m_layerState.positionChanged = true; + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setAnchorPoint(const FloatPoint3D& p) +{ + if (anchorPoint() == p) + return; + + GraphicsLayer::setAnchorPoint(p); + m_layerState.anchorPointChanged = true; + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setSize(const FloatSize& size) +{ + if (this->size() == size) + return; + + GraphicsLayer::setSize(size); + m_layerState.sizeChanged = true; + + if (maskLayer()) + maskLayer()->setSize(size); + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setTransform(const TransformationMatrix& t) +{ + if (transform() == t) + return; + + GraphicsLayer::setTransform(t); + m_layerState.transformChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setChildrenTransform(const TransformationMatrix& t) +{ + if (childrenTransform() == t) + return; + + GraphicsLayer::setChildrenTransform(t); + m_layerState.childrenTransformChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setPreserves3D(bool b) +{ + if (preserves3D() == b) + return; + + GraphicsLayer::setPreserves3D(b); + m_layerState.preserves3D = b; + m_layerState.flagsChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setMasksToBounds(bool b) +{ + if (masksToBounds() == b) + return; + GraphicsLayer::setMasksToBounds(b); + m_layerState.masksToBounds = b; + m_layerState.flagsChanged = true; + + didChangeGeometry(); +} + +void CoordinatedGraphicsLayer::setDrawsContent(bool b) +{ + if (drawsContent() == b) + return; + GraphicsLayer::setDrawsContent(b); + m_layerState.drawsContent = b; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsVisible(bool b) +{ + if (contentsAreVisible() == b) + return; + GraphicsLayer::setContentsVisible(b); + m_layerState.contentsVisible = b; + m_layerState.flagsChanged = true; + + if (maskLayer()) + maskLayer()->setContentsVisible(b); + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsOpaque(bool b) +{ + if (contentsOpaque() == b) + return; + if (m_mainBackingStore) + m_mainBackingStore->setSupportsAlpha(!b); + GraphicsLayer::setContentsOpaque(b); + m_layerState.contentsOpaque = b; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setBackfaceVisibility(bool b) +{ + if (backfaceVisibility() == b) + return; + + GraphicsLayer::setBackfaceVisibility(b); + m_layerState.backfaceVisible = b; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setOpacity(float opacity) +{ + if (this->opacity() == opacity) + return; + + GraphicsLayer::setOpacity(opacity); + m_layerState.opacity = opacity; + m_layerState.opacityChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsRect(const FloatRect& r) +{ + if (contentsRect() == r) + return; + + GraphicsLayer::setContentsRect(r); + m_layerState.contentsRect = r; + m_layerState.contentsRectChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsTileSize(const FloatSize& s) +{ + if (contentsTileSize() == s) + return; + + GraphicsLayer::setContentsTileSize(s); + m_layerState.contentsTileSize = s; + m_layerState.contentsTilingChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsTilePhase(const FloatSize& p) +{ + if (contentsTilePhase() == p) + return; + + GraphicsLayer::setContentsTilePhase(p); + m_layerState.contentsTilePhase = p; + m_layerState.contentsTilingChanged = true; + didChangeLayerState(); +} + +bool GraphicsLayer::supportsContentsTiling() +{ + return true; +} + +void CoordinatedGraphicsLayer::setContentsNeedsDisplay() +{ +#if USE(COORDINATED_GRAPHICS_THREADED) + if (m_platformLayer) + m_shouldUpdatePlatformLayer = true; +#endif + + notifyFlushRequired(); + addRepaintRect(contentsRect()); +} + +void CoordinatedGraphicsLayer::setContentsToPlatformLayer(PlatformLayer* platformLayer, ContentsLayerPurpose) +{ +#if USE(COORDINATED_GRAPHICS_THREADED) + if (m_platformLayer != platformLayer) + m_shouldSyncPlatformLayer = true; + + m_platformLayer = platformLayer; + notifyFlushRequired(); +#else + UNUSED_PARAM(platformLayer); +#endif +} + +bool CoordinatedGraphicsLayer::filtersCanBeComposited(const FilterOperations& filters) const +{ + if (!filters.size()) + return false; + + for (const auto& filterOperation : filters.operations()) { + if (filterOperation->type() == FilterOperation::REFERENCE) + return false; + } + + return true; +} + +bool CoordinatedGraphicsLayer::setFilters(const FilterOperations& newFilters) +{ + bool canCompositeFilters = filtersCanBeComposited(newFilters); + if (filters() == newFilters) + return canCompositeFilters; + + if (canCompositeFilters) { + if (!GraphicsLayer::setFilters(newFilters)) + return false; + didChangeFilters(); + } else if (filters().size()) { + clearFilters(); + didChangeFilters(); + } + + return canCompositeFilters; +} + +void CoordinatedGraphicsLayer::setContentsToSolidColor(const Color& color) +{ + if (m_layerState.solidColor == color) + return; + + m_layerState.solidColor = color; + m_layerState.solidColorChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setShowDebugBorder(bool show) +{ + if (isShowingDebugBorder() == show) + return; + + GraphicsLayer::setShowDebugBorder(show); + m_layerState.showDebugBorders = true; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setShowRepaintCounter(bool show) +{ + if (isShowingRepaintCounter() == show) + return; + + GraphicsLayer::setShowRepaintCounter(show); + m_layerState.showRepaintCounter = true; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setContentsToImage(Image* image) +{ + NativeImagePtr nativeImagePtr = image ? image->nativeImageForCurrentFrame() : nullptr; + if (m_compositedImage == image && m_compositedNativeImagePtr == nativeImagePtr) + return; + + m_compositedImage = image; + m_compositedNativeImagePtr = nativeImagePtr; + + GraphicsLayer::setContentsToImage(image); + didChangeImageBacking(); +} + +void CoordinatedGraphicsLayer::setMaskLayer(GraphicsLayer* layer) +{ + if (layer == maskLayer()) + return; + + GraphicsLayer::setMaskLayer(layer); + + if (!layer) + return; + + layer->setSize(size()); + layer->setContentsVisible(contentsAreVisible()); + auto& coordinatedLayer = downcast<CoordinatedGraphicsLayer>(*layer); + coordinatedLayer.didChangeLayerState(); + + m_layerState.mask = coordinatedLayer.id(); + m_layerState.maskChanged = true; + + didChangeLayerState(); +} + +bool CoordinatedGraphicsLayer::shouldDirectlyCompositeImage(Image* image) const +{ + if (!image || !image->isBitmapImage()) + return false; + + enum { MaxDimenstionForDirectCompositing = 2000 }; + if (image->width() > MaxDimenstionForDirectCompositing || image->height() > MaxDimenstionForDirectCompositing) + return false; + + return true; +} + +void CoordinatedGraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer) +{ + if (layer == replicaLayer()) + return; + + GraphicsLayer::setReplicatedByLayer(layer); + m_layerState.replica = toCoordinatedLayerID(layer); + m_layerState.replicaChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setNeedsDisplay() +{ + setNeedsDisplayInRect(FloatRect(FloatPoint(), size())); +} + +void CoordinatedGraphicsLayer::setNeedsDisplayInRect(const FloatRect& rect, ShouldClipToLayer) +{ + if (m_mainBackingStore) + m_mainBackingStore->invalidate(IntRect(rect)); + + didChangeLayerState(); + + addRepaintRect(rect); +} + +void CoordinatedGraphicsLayer::setScrollableArea(ScrollableArea* scrollableArea) +{ + bool oldScrollable = isScrollable(); + m_scrollableArea = scrollableArea; + if (oldScrollable == isScrollable()) + return; + + m_layerState.isScrollable = isScrollable(); + m_layerState.flagsChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::commitScrollOffset(const IntSize& offset) +{ + if (!isScrollable() || offset.isZero()) + return; + + m_scrollableArea->notifyScrollPositionChanged(m_scrollableArea->scrollPosition() + offset); + m_layerState.committedScrollOffset += offset; + m_layerState.committedScrollOffsetChanged = true; + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setFixedToViewport(bool isFixed) +{ + if (m_fixedToViewport == isFixed) + return; + + m_fixedToViewport = isFixed; + m_layerState.fixedToViewport = isFixed; + m_layerState.flagsChanged = true; + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::flushCompositingState(const FloatRect& rect) +{ + if (CoordinatedGraphicsLayer* mask = downcast<CoordinatedGraphicsLayer>(maskLayer())) + mask->flushCompositingStateForThisLayerOnly(); + + if (CoordinatedGraphicsLayer* replica = downcast<CoordinatedGraphicsLayer>(replicaLayer())) + replica->flushCompositingStateForThisLayerOnly(); + + flushCompositingStateForThisLayerOnly(); + + for (auto& child : children()) + child->flushCompositingState(rect); +} + +void CoordinatedGraphicsLayer::syncChildren() +{ + if (!m_shouldSyncChildren) + return; + m_shouldSyncChildren = false; + m_layerState.childrenChanged = true; + m_layerState.children.clear(); + for (auto& child : children()) + m_layerState.children.append(toCoordinatedLayerID(child)); +} + +void CoordinatedGraphicsLayer::syncFilters() +{ + if (!m_shouldSyncFilters) + return; + m_shouldSyncFilters = false; + + m_layerState.filters = GraphicsLayer::filters(); + m_layerState.filtersChanged = true; +} + +void CoordinatedGraphicsLayer::syncImageBacking() +{ + if (!m_shouldSyncImageBacking) + return; + m_shouldSyncImageBacking = false; + + if (m_compositedNativeImagePtr) { + ASSERT(!shouldHaveBackingStore()); + ASSERT(m_compositedImage); + + bool imageInstanceReplaced = m_coordinatedImageBacking && (m_coordinatedImageBacking->id() != CoordinatedImageBacking::getCoordinatedImageBackingID(m_compositedImage.get())); + if (imageInstanceReplaced) + releaseImageBackingIfNeeded(); + + if (!m_coordinatedImageBacking) { + m_coordinatedImageBacking = m_coordinator->createImageBackingIfNeeded(m_compositedImage.get()); + m_coordinatedImageBacking->addHost(this); + m_layerState.imageID = m_coordinatedImageBacking->id(); + } + + m_coordinatedImageBacking->markDirty(); + m_layerState.imageChanged = true; + } else + releaseImageBackingIfNeeded(); +} + +void CoordinatedGraphicsLayer::syncLayerState() +{ + if (!m_shouldSyncLayerState) + return; + m_shouldSyncLayerState = false; + + m_layerState.childrenTransform = childrenTransform(); + m_layerState.contentsRect = contentsRect(); + m_layerState.mask = toCoordinatedLayerID(maskLayer()); + m_layerState.opacity = opacity(); + m_layerState.replica = toCoordinatedLayerID(replicaLayer()); + m_layerState.transform = transform(); + + m_layerState.anchorPoint = m_adjustedAnchorPoint; + m_layerState.pos = m_adjustedPosition; + m_layerState.size = m_adjustedSize; + + if (m_layerState.flagsChanged) { + m_layerState.contentsOpaque = contentsOpaque(); + m_layerState.drawsContent = drawsContent(); + m_layerState.contentsVisible = contentsAreVisible(); + m_layerState.backfaceVisible = backfaceVisibility(); + m_layerState.masksToBounds = masksToBounds(); + m_layerState.preserves3D = preserves3D(); + m_layerState.fixedToViewport = fixedToViewport(); + m_layerState.showDebugBorders = isShowingDebugBorder(); + m_layerState.showRepaintCounter = isShowingRepaintCounter(); + m_layerState.isScrollable = isScrollable(); + } + + if (m_layerState.showDebugBorders) + updateDebugIndicators(); +} + +void CoordinatedGraphicsLayer::setDebugBorder(const Color& color, float width) +{ + ASSERT(m_layerState.showDebugBorders); + if (m_layerState.debugBorderColor != color) { + m_layerState.debugBorderColor = color; + m_layerState.debugBorderColorChanged = true; + } + + if (m_layerState.debugBorderWidth != width) { + m_layerState.debugBorderWidth = width; + m_layerState.debugBorderWidthChanged = true; + } +} + +void CoordinatedGraphicsLayer::syncAnimations() +{ + if (!m_shouldSyncAnimations) + return; + + m_shouldSyncAnimations = false; + m_layerState.animations = m_animations.getActiveAnimations(); + m_layerState.animationsChanged = true; +} + +void CoordinatedGraphicsLayer::syncPlatformLayer() +{ +#if USE(COORDINATED_GRAPHICS_THREADED) + if (!m_shouldSyncPlatformLayer) + return; + + m_shouldSyncPlatformLayer = false; + m_layerState.platformLayerChanged = true; + if (m_platformLayer) + m_layerState.platformLayerProxy = m_platformLayer->proxy(); +#endif +} + +void CoordinatedGraphicsLayer::updatePlatformLayer() +{ +#if USE(COORDINATED_GRAPHICS_THREADED) + if (!m_shouldUpdatePlatformLayer) + return; + + m_shouldUpdatePlatformLayer = false; + if (m_platformLayer) + m_platformLayer->swapBuffersIfNeeded(); +#endif +} + +void CoordinatedGraphicsLayer::flushCompositingStateForThisLayerOnly() +{ + // When we have a transform animation, we need to update visible rect every frame to adjust the visible rect of a backing store. + bool hasActiveTransformAnimation = selfOrAncestorHasActiveTransformAnimation(); + if (hasActiveTransformAnimation) + m_movingVisibleRect = true; + + // Sets the values. + computePixelAlignment(m_adjustedPosition, m_adjustedSize, m_adjustedAnchorPoint, m_pixelAlignmentOffset); + + syncImageBacking(); + syncLayerState(); + syncAnimations(); + computeTransformedVisibleRect(); + syncChildren(); + syncFilters(); + syncPlatformLayer(); + updatePlatformLayer(); + + // Only unset m_movingVisibleRect after we have updated the visible rect after the animation stopped. + if (!hasActiveTransformAnimation) + m_movingVisibleRect = false; +} + +void CoordinatedGraphicsLayer::syncPendingStateChangesIncludingSubLayers() +{ + if (m_layerState.hasPendingChanges()) { + m_coordinator->syncLayerState(m_id, m_layerState); + resetLayerState(); + } + + if (maskLayer()) + downcast<CoordinatedGraphicsLayer>(*maskLayer()).syncPendingStateChangesIncludingSubLayers(); + + for (auto& child : children()) + downcast<CoordinatedGraphicsLayer>(*child).syncPendingStateChangesIncludingSubLayers(); +} + +void CoordinatedGraphicsLayer::resetLayerState() +{ + m_layerState.changeMask = 0; + m_layerState.tilesToCreate.clear(); + m_layerState.tilesToRemove.clear(); + m_layerState.tilesToUpdate.clear(); + m_layerState.committedScrollOffset = IntSize(); +} + +bool CoordinatedGraphicsLayer::imageBackingVisible() +{ + ASSERT(m_coordinatedImageBacking); + return transformedVisibleRect().intersects(IntRect(contentsRect())); +} + +void CoordinatedGraphicsLayer::releaseImageBackingIfNeeded() +{ + if (!m_coordinatedImageBacking) + return; + + ASSERT(m_coordinator); + m_coordinatedImageBacking->removeHost(this); + m_coordinatedImageBacking = nullptr; + m_layerState.imageID = InvalidCoordinatedImageBackingID; + m_layerState.imageChanged = true; +} + +CoordinatedGraphicsLayer* CoordinatedGraphicsLayer::findFirstDescendantWithContentsRecursively() +{ + if (shouldHaveBackingStore()) + return this; + + for (auto& child : children()) { + if (CoordinatedGraphicsLayer* layer = downcast<CoordinatedGraphicsLayer>(*child).findFirstDescendantWithContentsRecursively()) + return layer; + } + + return nullptr; +} + +void CoordinatedGraphicsLayer::setVisibleContentRectTrajectoryVector(const FloatPoint& trajectoryVector) +{ + if (!m_mainBackingStore) + return; + + m_mainBackingStore->setTrajectoryVector(trajectoryVector); + setNeedsVisibleRectAdjustment(); +} + +void CoordinatedGraphicsLayer::deviceOrPageScaleFactorChanged() +{ + if (shouldHaveBackingStore()) + m_pendingContentsScaleAdjustment = true; +} + +float CoordinatedGraphicsLayer::effectiveContentsScale() +{ + return selfOrAncestorHaveNonAffineTransforms() ? 1 : deviceScaleFactor() * pageScaleFactor(); +} + +void CoordinatedGraphicsLayer::adjustContentsScale() +{ + ASSERT(shouldHaveBackingStore()); + if (!m_mainBackingStore || m_mainBackingStore->contentsScale() == effectiveContentsScale()) + return; + + // Between creating the new backing store and painting the content, + // we do not want to drop the previous one as that might result in + // briefly seeing flickering as the old tiles may be dropped before + // something replaces them. + m_previousBackingStore = WTFMove(m_mainBackingStore); + + // No reason to save the previous backing store for non-visible areas. + m_previousBackingStore->removeAllNonVisibleTiles(transformedVisibleRect(), IntRect(0, 0, size().width(), size().height())); +} + +void CoordinatedGraphicsLayer::createBackingStore() +{ + m_mainBackingStore = std::make_unique<TiledBackingStore>(this, effectiveContentsScale()); + m_mainBackingStore->setSupportsAlpha(!contentsOpaque()); +} + +void CoordinatedGraphicsLayer::tiledBackingStorePaint(GraphicsContext& context, const IntRect& rect) +{ + if (rect.isEmpty()) + return; + paintGraphicsLayerContents(context, rect); +} + +void CoordinatedGraphicsLayer::didUpdateTileBuffers() +{ + if (!isShowingRepaintCounter()) + return; + + m_layerState.repaintCount = incrementRepaintCount(); + m_layerState.repaintCountChanged = true; +} + +void CoordinatedGraphicsLayer::tiledBackingStoreHasPendingTileCreation() +{ + setNeedsVisibleRectAdjustment(); + notifyFlushRequired(); +} + +static void clampToContentsRectIfRectIsInfinite(FloatRect& rect, const FloatSize& contentsSize) +{ + if (rect.width() >= LayoutUnit::nearlyMax() || rect.width() <= LayoutUnit::nearlyMin()) { + rect.setX(0); + rect.setWidth(contentsSize.width()); + } + + if (rect.height() >= LayoutUnit::nearlyMax() || rect.height() <= LayoutUnit::nearlyMin()) { + rect.setY(0); + rect.setHeight(contentsSize.height()); + } +} + +IntRect CoordinatedGraphicsLayer::transformedVisibleRect() +{ + // Non-invertible layers are not visible. + if (!m_layerTransform.combined().isInvertible()) + return IntRect(); + + // Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates). + // The resulting quad might be squewed and the visible rect is the bounding box of this quad, + // so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier). + ASSERT(m_cachedInverseTransform == m_layerTransform.combined().inverse().value_or(TransformationMatrix())); + FloatRect rect = m_cachedInverseTransform.clampedBoundsOfProjectedQuad(FloatQuad(m_coordinator->visibleContentsRect())); + clampToContentsRectIfRectIsInfinite(rect, size()); + return enclosingIntRect(rect); +} + +bool CoordinatedGraphicsLayer::paintToSurface(const IntSize& size, uint32_t& atlas, IntPoint& offset, CoordinatedSurface::Client& client) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges()); + return m_coordinator->paintToSurface(size, contentsOpaque() ? CoordinatedSurface::NoFlags : CoordinatedSurface::SupportsAlpha, atlas, offset, client); +} + +void CoordinatedGraphicsLayer::createTile(uint32_t tileID, float scaleFactor) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges()); + + TileCreationInfo creationInfo; + creationInfo.tileID = tileID; + creationInfo.scale = scaleFactor; + m_layerState.tilesToCreate.append(creationInfo); +} + +void CoordinatedGraphicsLayer::updateTile(uint32_t tileID, const SurfaceUpdateInfo& updateInfo, const IntRect& tileRect) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges()); + + TileUpdateInfo tileUpdateInfo; + tileUpdateInfo.tileID = tileID; + tileUpdateInfo.tileRect = tileRect; + tileUpdateInfo.updateInfo = updateInfo; + m_layerState.tilesToUpdate.append(tileUpdateInfo); +} + +void CoordinatedGraphicsLayer::removeTile(uint32_t tileID) +{ + ASSERT(m_coordinator); + ASSERT(m_coordinator->isFlushingLayerChanges() || m_isPurging); + m_layerState.tilesToRemove.append(tileID); +} + +void CoordinatedGraphicsLayer::updateContentBuffersIncludingSubLayers() +{ + if (CoordinatedGraphicsLayer* mask = downcast<CoordinatedGraphicsLayer>(maskLayer())) + mask->updateContentBuffers(); + + if (CoordinatedGraphicsLayer* replica = downcast<CoordinatedGraphicsLayer>(replicaLayer())) + replica->updateContentBuffers(); + + updateContentBuffers(); + + for (auto& child : children()) + downcast<CoordinatedGraphicsLayer>(*child).updateContentBuffersIncludingSubLayers(); +} + +void CoordinatedGraphicsLayer::updateContentBuffers() +{ + if (!shouldHaveBackingStore()) { + m_mainBackingStore = nullptr; + m_previousBackingStore = nullptr; + return; + } + + if (m_pendingContentsScaleAdjustment) { + adjustContentsScale(); + m_pendingContentsScaleAdjustment = false; + } + + // This is the only place we (re)create the main tiled backing store, once we + // have a remote client and we are ready to send our data to the UI process. + if (!m_mainBackingStore) { + createBackingStore(); + m_pendingVisibleRectAdjustment = true; + } + + if (m_pendingVisibleRectAdjustment) { + m_pendingVisibleRectAdjustment = false; + m_mainBackingStore->createTilesIfNeeded(transformedVisibleRect(), IntRect(0, 0, size().width(), size().height())); + } + + m_mainBackingStore->updateTileBuffers(); + + // The previous backing store is kept around to avoid flickering between + // removing the existing tiles and painting the new ones. The first time + // the visibleRect is full painted we remove the previous backing store. + if (m_mainBackingStore->visibleAreaIsCovered()) + m_previousBackingStore = nullptr; +} + +void CoordinatedGraphicsLayer::purgeBackingStores() +{ +#ifndef NDEBUG + SetForScope<bool> updateModeProtector(m_isPurging, true); +#endif + m_mainBackingStore = nullptr; + m_previousBackingStore = nullptr; + + releaseImageBackingIfNeeded(); + + didChangeLayerState(); +} + +void CoordinatedGraphicsLayer::setCoordinator(CoordinatedGraphicsLayerClient* coordinator) +{ + m_coordinator = coordinator; +} + +void CoordinatedGraphicsLayer::setNeedsVisibleRectAdjustment() +{ + if (shouldHaveBackingStore()) + m_pendingVisibleRectAdjustment = true; +} + +static inline bool isIntegral(float value) +{ + return static_cast<int>(value) == value; +} + +FloatPoint CoordinatedGraphicsLayer::computePositionRelativeToBase() +{ + FloatPoint offset; + for (const GraphicsLayer* currLayer = this; currLayer; currLayer = currLayer->parent()) + offset += currLayer->position(); + + return offset; +} + +void CoordinatedGraphicsLayer::computePixelAlignment(FloatPoint& position, FloatSize& size, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset) +{ + if (isIntegral(effectiveContentsScale())) { + position = m_position; + size = m_size; + anchorPoint = m_anchorPoint; + alignmentOffset = FloatSize(); + return; + } + + FloatPoint positionRelativeToBase = computePositionRelativeToBase(); + + FloatRect baseRelativeBounds(positionRelativeToBase, m_size); + FloatRect scaledBounds = baseRelativeBounds; + + // Scale by the effective scale factor to compute the screen-relative bounds. + scaledBounds.scale(effectiveContentsScale()); + + // Round to integer boundaries. + // NOTE: When using enclosingIntRect (as mac) it will have different sizes depending on position. + FloatRect alignedBounds = enclosingIntRect(scaledBounds); + + // Convert back to layer coordinates. + alignedBounds.scale(1 / effectiveContentsScale()); + + // Convert back to layer coordinates. + alignmentOffset = baseRelativeBounds.location() - alignedBounds.location(); + + position = m_position - alignmentOffset; + size = alignedBounds.size(); + + // Now we have to compute a new anchor point which compensates for rounding. + float anchorPointX = m_anchorPoint.x(); + float anchorPointY = m_anchorPoint.y(); + + if (alignedBounds.width()) + anchorPointX = (baseRelativeBounds.width() * anchorPointX + alignmentOffset.width()) / alignedBounds.width(); + + if (alignedBounds.height()) + anchorPointY = (baseRelativeBounds.height() * anchorPointY + alignmentOffset.height()) / alignedBounds.height(); + + anchorPoint = FloatPoint3D(anchorPointX, anchorPointY, m_anchorPoint.z() * effectiveContentsScale()); +} + +void CoordinatedGraphicsLayer::computeTransformedVisibleRect() +{ + if (!m_shouldUpdateVisibleRect && !m_movingVisibleRect) + return; + + m_shouldUpdateVisibleRect = false; + TransformationMatrix currentTransform = transform(); + if (m_movingVisibleRect) + client().getCurrentTransform(this, currentTransform); + m_layerTransform.setLocalTransform(currentTransform); + + m_layerTransform.setAnchorPoint(m_adjustedAnchorPoint); + m_layerTransform.setPosition(m_adjustedPosition); + m_layerTransform.setSize(m_adjustedSize); + + m_layerTransform.setFlattening(!preserves3D()); + m_layerTransform.setChildrenTransform(childrenTransform()); + m_layerTransform.combineTransforms(parent() ? downcast<CoordinatedGraphicsLayer>(*parent()).m_layerTransform.combinedForChildren() : TransformationMatrix()); + + m_cachedInverseTransform = m_layerTransform.combined().inverse().value_or(TransformationMatrix()); + + // The combined transform will be used in tiledBackingStoreVisibleRect. + setNeedsVisibleRectAdjustment(); +} + +bool CoordinatedGraphicsLayer::shouldHaveBackingStore() const +{ + return drawsContent() && contentsAreVisible() && !m_size.isEmpty(); +} + +bool CoordinatedGraphicsLayer::selfOrAncestorHasActiveTransformAnimation() const +{ + if (m_animations.hasActiveAnimationsOfType(AnimatedPropertyTransform)) + return true; + + if (!parent()) + return false; + + return downcast<CoordinatedGraphicsLayer>(*parent()).selfOrAncestorHasActiveTransformAnimation(); +} + +bool CoordinatedGraphicsLayer::selfOrAncestorHaveNonAffineTransforms() +{ + if (m_animations.hasActiveAnimationsOfType(AnimatedPropertyTransform)) + return true; + + if (!m_layerTransform.combined().isAffine()) + return true; + + if (!parent()) + return false; + + return downcast<CoordinatedGraphicsLayer>(*parent()).selfOrAncestorHaveNonAffineTransforms(); +} + +bool CoordinatedGraphicsLayer::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& keyframesName, double delayAsNegativeTimeOffset) +{ + ASSERT(!keyframesName.isEmpty()); + + if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyTransform && valueList.property() != AnimatedPropertyOpacity && valueList.property() != AnimatedPropertyFilter)) + return false; + + if (valueList.property() == AnimatedPropertyFilter) { + int listIndex = validateFilterOperations(valueList); + if (listIndex < 0) + return false; + + const auto& filters = static_cast<const FilterAnimationValue&>(valueList.at(listIndex)).value(); + if (!filtersCanBeComposited(filters)) + return false; + } + + bool listsMatch = false; + bool ignoredHasBigRotation; + + if (valueList.property() == AnimatedPropertyTransform) + listsMatch = validateTransformOperations(valueList, ignoredHasBigRotation) >= 0; + + m_lastAnimationStartTime = monotonicallyIncreasingTime() - delayAsNegativeTimeOffset; + m_animations.add(TextureMapperAnimation(keyframesName, valueList, boxSize, *anim, listsMatch, m_lastAnimationStartTime, 0, TextureMapperAnimation::AnimationState::Playing)); + m_animationStartedTimer.startOneShot(0); + didChangeAnimations(); + return true; +} + +void CoordinatedGraphicsLayer::pauseAnimation(const String& animationName, double time) +{ + m_animations.pause(animationName, time); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::removeAnimation(const String& animationName) +{ + m_animations.remove(animationName); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::suspendAnimations(double time) +{ + m_animations.suspend(time); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::resumeAnimations() +{ + m_animations.resume(); + didChangeAnimations(); +} + +void CoordinatedGraphicsLayer::animationStartedTimerFired() +{ + client().notifyAnimationStarted(this, "", m_lastAnimationStartTime); +} + +#if USE(COORDINATED_GRAPHICS_THREADED) +void CoordinatedGraphicsLayer::platformLayerWillBeDestroyed() +{ +} + +void CoordinatedGraphicsLayer::setPlatformLayerNeedsDisplay() +{ +} +#endif + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h new file mode 100644 index 000000000..bf25111db --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsLayer.h @@ -0,0 +1,246 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + + +#ifndef CoordinatedGraphicsLayer_h +#define CoordinatedGraphicsLayer_h + +#if USE(COORDINATED_GRAPHICS) + +#include "CoordinatedGraphicsState.h" +#include "CoordinatedImageBacking.h" +#include "FloatPoint3D.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerTransform.h" +#include "Image.h" +#include "IntSize.h" +#include "TextureMapperAnimation.h" +#include "TextureMapperPlatformLayer.h" +#include "TiledBackingStore.h" +#include "TiledBackingStoreClient.h" +#include "TransformationMatrix.h" +#include <wtf/text/StringHash.h> + +namespace WebCore { +class CoordinatedGraphicsLayer; +class TextureMapperAnimations; +class ScrollableArea; + +class CoordinatedGraphicsLayerClient { +public: + virtual bool isFlushingLayerChanges() const = 0; + virtual FloatRect visibleContentsRect() const = 0; + virtual Ref<CoordinatedImageBacking> createImageBackingIfNeeded(Image*) = 0; + virtual void detachLayer(CoordinatedGraphicsLayer*) = 0; + virtual bool paintToSurface(const IntSize&, CoordinatedSurface::Flags, uint32_t& atlasID, IntPoint&, CoordinatedSurface::Client&) = 0; + + virtual void syncLayerState(CoordinatedLayerID, CoordinatedGraphicsLayerState&) = 0; +}; + +class CoordinatedGraphicsLayer : public GraphicsLayer + , public TiledBackingStoreClient +#if USE(COORDINATED_GRAPHICS_THREADED) + , public TextureMapperPlatformLayer::Client +#endif + , public CoordinatedImageBacking::Host { +public: + explicit CoordinatedGraphicsLayer(Type, GraphicsLayerClient&); + virtual ~CoordinatedGraphicsLayer(); + + PlatformLayerID primaryLayerID() const override { return id(); } + + // Reimplementations from GraphicsLayer.h. + bool setChildren(const Vector<GraphicsLayer*>&) override; + void addChild(GraphicsLayer*) override; + void addChildAtIndex(GraphicsLayer*, int) override; + void addChildAbove(GraphicsLayer*, GraphicsLayer*) override; + void addChildBelow(GraphicsLayer*, GraphicsLayer*) override; + bool replaceChild(GraphicsLayer*, GraphicsLayer*) override; + void removeFromParent() override; + void setPosition(const FloatPoint&) override; + void setAnchorPoint(const FloatPoint3D&) override; + void setSize(const FloatSize&) override; + void setTransform(const TransformationMatrix&) override; + void setChildrenTransform(const TransformationMatrix&) override; + void setPreserves3D(bool) override; + void setMasksToBounds(bool) override; + void setDrawsContent(bool) override; + void setContentsVisible(bool) override; + void setContentsOpaque(bool) override; + void setBackfaceVisibility(bool) override; + void setOpacity(float) override; + void setContentsRect(const FloatRect&) override; + void setContentsTilePhase(const FloatSize&) override; + void setContentsTileSize(const FloatSize&) override; + void setContentsToImage(Image*) override; + void setContentsToSolidColor(const Color&) override; + void setShowDebugBorder(bool) override; + void setShowRepaintCounter(bool) override; + bool shouldDirectlyCompositeImage(Image*) const override; + void setContentsToPlatformLayer(PlatformLayer*, ContentsLayerPurpose) override; + void setMaskLayer(GraphicsLayer*) override; + void setReplicatedByLayer(GraphicsLayer*) override; + void setNeedsDisplay() override; + void setNeedsDisplayInRect(const FloatRect&, ShouldClipToLayer = ClipToLayer) override; + void setContentsNeedsDisplay() override; + void deviceOrPageScaleFactorChanged() override; + void flushCompositingState(const FloatRect&) override; + void flushCompositingStateForThisLayerOnly() override; + bool setFilters(const FilterOperations&) override; + bool addAnimation(const KeyframeValueList&, const FloatSize&, const Animation*, const String&, double) override; + void pauseAnimation(const String&, double) override; + void removeAnimation(const String&) override; + void suspendAnimations(double time) override; + void resumeAnimations() override; + bool usesContentsLayer() const override { return m_platformLayer || m_compositedImage; } + + void syncPendingStateChangesIncludingSubLayers(); + void updateContentBuffersIncludingSubLayers(); + + FloatPoint computePositionRelativeToBase(); + void computePixelAlignment(FloatPoint& position, FloatSize&, FloatPoint3D& anchorPoint, FloatSize& alignmentOffset); + + void setVisibleContentRectTrajectoryVector(const FloatPoint&); + + void setScrollableArea(ScrollableArea*); + bool isScrollable() const { return !!m_scrollableArea; } + void commitScrollOffset(const IntSize&); + + CoordinatedLayerID id() const { return m_id; } + + void setFixedToViewport(bool isFixed); + + IntRect coverRect() const { return m_mainBackingStore ? m_mainBackingStore->mapToContents(m_mainBackingStore->coverRect()) : IntRect(); } + IntRect transformedVisibleRect(); + + // TiledBackingStoreClient + void tiledBackingStorePaint(GraphicsContext&, const IntRect&) override; + void didUpdateTileBuffers() override; + void tiledBackingStoreHasPendingTileCreation() override; + void createTile(uint32_t tileID, float) override; + void updateTile(uint32_t tileID, const SurfaceUpdateInfo&, const IntRect&) override; + void removeTile(uint32_t tileID) override; + bool paintToSurface(const IntSize&, uint32_t& /* atlasID */, IntPoint&, CoordinatedSurface::Client&) override; + + void setCoordinator(CoordinatedGraphicsLayerClient*); + + void setNeedsVisibleRectAdjustment(); + void purgeBackingStores(); + + CoordinatedGraphicsLayer* findFirstDescendantWithContentsRecursively(); + +private: + bool isCoordinatedGraphicsLayer() const override { return true; } + + void syncPlatformLayer(); + void updatePlatformLayer(); +#if USE(COORDINATED_GRAPHICS_THREADED) + void platformLayerWillBeDestroyed() override; + void setPlatformLayerNeedsDisplay() override; +#endif + + void setDebugBorder(const Color&, float width) override; + + bool fixedToViewport() const { return m_fixedToViewport; } + + void didChangeLayerState(); + void didChangeAnimations(); + void didChangeGeometry(); + void didChangeChildren(); + void didChangeFilters(); + void didChangeImageBacking(); + + void resetLayerState(); + void syncLayerState(); + void syncAnimations(); + void syncChildren(); + void syncFilters(); + void syncImageBacking(); + void computeTransformedVisibleRect(); + void updateContentBuffers(); + + void createBackingStore(); + void releaseImageBackingIfNeeded(); + + void notifyFlushRequired(); + + // CoordinatedImageBacking::Host + bool imageBackingVisible() override; + bool shouldHaveBackingStore() const; + bool selfOrAncestorHasActiveTransformAnimation() const; + bool selfOrAncestorHaveNonAffineTransforms(); + void adjustContentsScale(); + + void setShouldUpdateVisibleRect(); + float effectiveContentsScale(); + + void animationStartedTimerFired(); + + bool filtersCanBeComposited(const FilterOperations&) const; + + CoordinatedLayerID m_id; + CoordinatedGraphicsLayerState m_layerState; + GraphicsLayerTransform m_layerTransform; + TransformationMatrix m_cachedInverseTransform; + FloatSize m_pixelAlignmentOffset; + FloatSize m_adjustedSize; + FloatPoint m_adjustedPosition; + FloatPoint3D m_adjustedAnchorPoint; + +#ifndef NDEBUG + bool m_isPurging; +#endif + bool m_shouldUpdateVisibleRect: 1; + bool m_shouldSyncLayerState: 1; + bool m_shouldSyncChildren: 1; + bool m_shouldSyncFilters: 1; + bool m_shouldSyncImageBacking: 1; + bool m_shouldSyncAnimations: 1; + bool m_fixedToViewport : 1; + bool m_movingVisibleRect : 1; + bool m_pendingContentsScaleAdjustment : 1; + bool m_pendingVisibleRectAdjustment : 1; +#if USE(COORDINATED_GRAPHICS_THREADED) + bool m_shouldSyncPlatformLayer : 1; + bool m_shouldUpdatePlatformLayer : 1; +#endif + + CoordinatedGraphicsLayerClient* m_coordinator; + std::unique_ptr<TiledBackingStore> m_mainBackingStore; + std::unique_ptr<TiledBackingStore> m_previousBackingStore; + + RefPtr<Image> m_compositedImage; + NativeImagePtr m_compositedNativeImagePtr; + RefPtr<CoordinatedImageBacking> m_coordinatedImageBacking; + + PlatformLayer* m_platformLayer; + Timer m_animationStartedTimer; + TextureMapperAnimations m_animations; + double m_lastAnimationStartTime { 0.0 }; + + ScrollableArea* m_scrollableArea; +}; + +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_GRAPHICSLAYER(WebCore::CoordinatedGraphicsLayer, isCoordinatedGraphicsLayer()) + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsLayer_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h new file mode 100644 index 000000000..c810530b5 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedGraphicsState.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2013 Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 CoordinatedGraphicsState_h +#define CoordinatedGraphicsState_h + +#if USE(COORDINATED_GRAPHICS) + +#include "Color.h" +#include "FilterOperations.h" +#include "FloatRect.h" +#include "FloatSize.h" +#include "IntRect.h" +#include "IntSize.h" +#include "SurfaceUpdateInfo.h" +#include "TextureMapperAnimation.h" +#include "TransformationMatrix.h" + +#if USE(COORDINATED_GRAPHICS_THREADED) +#include "TextureMapperPlatformLayerProxy.h" +#endif + +namespace WebCore { + +class CoordinatedSurface; + +typedef uint32_t CoordinatedLayerID; +enum { InvalidCoordinatedLayerID = 0 }; + +typedef uint64_t CoordinatedImageBackingID; +enum { InvalidCoordinatedImageBackingID = 0 }; + +struct TileUpdateInfo { + uint32_t tileID; + IntRect tileRect; + WebCore::SurfaceUpdateInfo updateInfo; +}; + +struct TileCreationInfo { + uint32_t tileID; + float scale; +}; + +struct CoordinatedGraphicsLayerState { + union { + struct { + bool positionChanged: 1; + bool anchorPointChanged: 1; + bool sizeChanged: 1; + bool transformChanged: 1; + bool childrenTransformChanged: 1; + bool contentsRectChanged: 1; + bool opacityChanged: 1; + bool solidColorChanged: 1; + bool debugBorderColorChanged: 1; + bool debugBorderWidthChanged: 1; + bool replicaChanged: 1; + bool maskChanged: 1; + bool imageChanged: 1; + bool flagsChanged: 1; + bool animationsChanged: 1; + bool filtersChanged: 1; + bool childrenChanged: 1; + bool repaintCountChanged : 1; + bool platformLayerChanged: 1; + bool platformLayerShouldSwapBuffers: 1; + bool isScrollableChanged: 1; + bool committedScrollOffsetChanged: 1; + bool contentsTilingChanged: 1; + }; + unsigned changeMask; + }; + union { + struct { + bool contentsOpaque : 1; + bool drawsContent : 1; + bool contentsVisible : 1; + bool backfaceVisible : 1; + bool masksToBounds : 1; + bool preserves3D : 1; + bool fixedToViewport : 1; + bool showDebugBorders : 1; + bool showRepaintCounter : 1; + bool isScrollable: 1; + }; + unsigned flags; + }; + + CoordinatedGraphicsLayerState() + : changeMask(0) + , contentsOpaque(false) + , drawsContent(false) + , contentsVisible(true) + , backfaceVisible(true) + , masksToBounds(false) + , preserves3D(false) + , fixedToViewport(false) + , showDebugBorders(false) + , showRepaintCounter(false) + , isScrollable(false) + , opacity(0) + , debugBorderWidth(0) + , replica(InvalidCoordinatedLayerID) + , mask(InvalidCoordinatedLayerID) + , imageID(InvalidCoordinatedImageBackingID) + , repaintCount(0) +#if USE(COORDINATED_GRAPHICS_THREADED) + , platformLayerProxy(0) +#endif + { + } + + FloatPoint pos; + FloatPoint3D anchorPoint; + FloatSize size; + TransformationMatrix transform; + TransformationMatrix childrenTransform; + FloatRect contentsRect; + FloatSize contentsTilePhase; + FloatSize contentsTileSize; + float opacity; + Color solidColor; + Color debugBorderColor; + float debugBorderWidth; + FilterOperations filters; + TextureMapperAnimations animations; + Vector<uint32_t> children; + Vector<TileCreationInfo> tilesToCreate; + Vector<uint32_t> tilesToRemove; + CoordinatedLayerID replica; + CoordinatedLayerID mask; + CoordinatedImageBackingID imageID; + + unsigned repaintCount; + Vector<TileUpdateInfo> tilesToUpdate; + +#if USE(COORDINATED_GRAPHICS_THREADED) + RefPtr<TextureMapperPlatformLayerProxy> platformLayerProxy; +#endif + + IntSize committedScrollOffset; + + bool hasPendingChanges() const + { + return changeMask || tilesToUpdate.size() || tilesToRemove.size() || tilesToCreate.size(); + } +}; + +struct CoordinatedGraphicsState { + uint32_t rootCompositingLayer; + FloatPoint scrollPosition; + IntSize contentsSize; + IntRect coveredRect; + + Vector<CoordinatedLayerID> layersToCreate; + Vector<std::pair<CoordinatedLayerID, CoordinatedGraphicsLayerState> > layersToUpdate; + Vector<CoordinatedLayerID> layersToRemove; + + Vector<CoordinatedImageBackingID> imagesToCreate; + Vector<CoordinatedImageBackingID> imagesToRemove; + Vector<std::pair<CoordinatedImageBackingID, RefPtr<CoordinatedSurface> > > imagesToUpdate; + Vector<CoordinatedImageBackingID> imagesToClear; + + Vector<std::pair<uint32_t /* atlasID */, RefPtr<CoordinatedSurface> > > updateAtlasesToCreate; + Vector<uint32_t /* atlasID */> updateAtlasesToRemove; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedGraphicsState_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.cpp new file mode 100644 index 000000000..3f5673e8f --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.cpp @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2012 Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 USE(COORDINATED_GRAPHICS) +#include "CoordinatedImageBacking.h" + +#include "CoordinatedGraphicsState.h" +#include "GraphicsContext.h" + +namespace WebCore { + +class ImageBackingSurfaceClient : public CoordinatedSurface::Client { +public: + ImageBackingSurfaceClient(Image& image, const IntRect& rect) + : m_image(image) + , m_rect(rect) + { + } + + void paintToSurfaceContext(GraphicsContext& context) override + { + context.drawImage(m_image, m_rect, m_rect); + } + +private: + Image& m_image; + IntRect m_rect; +}; + +CoordinatedImageBackingID CoordinatedImageBacking::getCoordinatedImageBackingID(Image* image) +{ + // CoordinatedImageBacking keeps a RefPtr<Image> member, so the same Image pointer can not refer two different instances until CoordinatedImageBacking releases the member. + return reinterpret_cast<CoordinatedImageBackingID>(image); +} + +PassRefPtr<CoordinatedImageBacking> CoordinatedImageBacking::create(Client* client, PassRefPtr<Image> image) +{ + return adoptRef(new CoordinatedImageBacking(client, image)); +} + +CoordinatedImageBacking::CoordinatedImageBacking(Client* client, PassRefPtr<Image> image) + : m_client(client) + , m_image(image) + , m_id(getCoordinatedImageBackingID(m_image.get())) + , m_clearContentsTimer(*this, &CoordinatedImageBacking::clearContentsTimerFired) + , m_isDirty(false) + , m_isVisible(false) +{ + // FIXME: We would need to decode a small image directly into a GraphicsSurface. + // http://webkit.org/b/101426 + + m_client->createImageBacking(id()); +} + +CoordinatedImageBacking::~CoordinatedImageBacking() +{ +} + +void CoordinatedImageBacking::addHost(Host* host) +{ + ASSERT(!m_hosts.contains(host)); + m_hosts.append(host); +} + +void CoordinatedImageBacking::removeHost(Host* host) +{ + size_t position = m_hosts.find(host); + ASSERT(position != notFound); + m_hosts.remove(position); + + if (m_hosts.isEmpty()) + m_client->removeImageBacking(id()); +} + +void CoordinatedImageBacking::markDirty() +{ + m_isDirty = true; +} + +void CoordinatedImageBacking::update() +{ + releaseSurfaceIfNeeded(); + + bool changedToVisible; + updateVisibilityIfNeeded(changedToVisible); + if (!m_isVisible) + return; + + if (!changedToVisible) { + if (!m_isDirty) + return; + + if (m_nativeImagePtr == m_image->nativeImageForCurrentFrame()) { + m_isDirty = false; + return; + } + } + + m_surface = CoordinatedSurface::create(IntSize(m_image->size()), !m_image->currentFrameKnownToBeOpaque() ? CoordinatedSurface::SupportsAlpha : CoordinatedSurface::NoFlags); + if (!m_surface) { + m_isDirty = false; + return; + } + + IntRect rect(IntPoint::zero(), IntSize(m_image->size())); + + ImageBackingSurfaceClient surfaceClient(*m_image, rect); + m_surface->paintToSurface(rect, surfaceClient); + + m_nativeImagePtr = m_image->nativeImageForCurrentFrame(); + + m_client->updateImageBacking(id(), m_surface.copyRef()); + m_isDirty = false; +} + +void CoordinatedImageBacking::releaseSurfaceIfNeeded() +{ + // We must keep m_surface until UI Process reads m_surface. + // If m_surface exists, it was created in the previous update. + m_surface = nullptr; +} + +static const double clearContentsTimerInterval = 3; + +void CoordinatedImageBacking::updateVisibilityIfNeeded(bool& changedToVisible) +{ + bool previousIsVisible = m_isVisible; + + m_isVisible = false; + for (auto& host : m_hosts) { + if (host->imageBackingVisible()) { + m_isVisible = true; + break; + } + } + + bool changedToInvisible = previousIsVisible && !m_isVisible; + if (changedToInvisible) { + ASSERT(!m_clearContentsTimer.isActive()); + m_clearContentsTimer.startOneShot(clearContentsTimerInterval); + } + + changedToVisible = !previousIsVisible && m_isVisible; + + if (m_isVisible && m_clearContentsTimer.isActive()) { + m_clearContentsTimer.stop(); + // We don't want to update the texture if we didn't remove the texture. + changedToVisible = false; + } +} + +void CoordinatedImageBacking::clearContentsTimerFired() +{ + m_client->clearImageBackingContents(id()); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.h new file mode 100644 index 000000000..b8603c68e --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedImageBacking.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 CoordinatedImageBacking_h +#define CoordinatedImageBacking_h + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedGraphicsState.h" +#include "CoordinatedSurface.h" +#include "Image.h" +#include "Timer.h" +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class CoordinatedImageBacking : public RefCounted<CoordinatedImageBacking> { +public: + class Client { + public: + virtual void createImageBacking(CoordinatedImageBackingID) = 0; + virtual void updateImageBacking(CoordinatedImageBackingID, RefPtr<CoordinatedSurface>&&) = 0; + virtual void clearImageBackingContents(CoordinatedImageBackingID) = 0; + virtual void removeImageBacking(CoordinatedImageBackingID) = 0; + }; + + class Host { + public: + virtual bool imageBackingVisible() = 0; + }; + + static PassRefPtr<CoordinatedImageBacking> create(Client*, PassRefPtr<Image>); + virtual ~CoordinatedImageBacking(); + + static CoordinatedImageBackingID getCoordinatedImageBackingID(Image*); + CoordinatedImageBackingID id() const { return m_id; } + + void addHost(Host*); + void removeHost(Host*); + + // When a new image is updated or an animated gif is progressed, CoordinatedGraphicsLayer calls markDirty(). + void markDirty(); + + // Create, remove or update its backing. + void update(); + +private: + CoordinatedImageBacking(Client*, PassRefPtr<Image>); + + void releaseSurfaceIfNeeded(); + void updateVisibilityIfNeeded(bool& changedToVisible); + void clearContentsTimerFired(); + + Client* m_client; + RefPtr<Image> m_image; + NativeImagePtr m_nativeImagePtr; + CoordinatedImageBackingID m_id; + Vector<Host*> m_hosts; + + RefPtr<CoordinatedSurface> m_surface; + + Timer m_clearContentsTimer; + + bool m_isDirty; + bool m_isVisible; + +}; + +} // namespace WebCore +#endif // USE(COORDINATED_GRAPHICS) + +#endif // CoordinatedImageBacking_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.cpp new file mode 100644 index 000000000..e0d815bd0 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Company 100, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" +#include "CoordinatedSurface.h" + +#if USE(COORDINATED_GRAPHICS) + +namespace WebCore { + +CoordinatedSurface::Factory* CoordinatedSurface::s_factory = 0; + +void CoordinatedSurface::setFactory(CoordinatedSurface::Factory factory) +{ + s_factory = factory; +} + +RefPtr<CoordinatedSurface> CoordinatedSurface::create(const IntSize& size, Flags flags) +{ + ASSERT(s_factory); + return s_factory(size, flags); +} + +CoordinatedSurface::CoordinatedSurface(const IntSize& size, Flags flags) + : m_size(size) + , m_flags(flags) +{ +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.h b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.h new file mode 100644 index 000000000..ac9ae1712 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedSurface.h @@ -0,0 +1,76 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2012 Company 100, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef CoordinatedSurface_h +#define CoordinatedSurface_h + +#if USE(COORDINATED_GRAPHICS) +#include "IntRect.h" +#include <wtf/RefPtr.h> +#include <wtf/ThreadSafeRefCounted.h> + +namespace WebCore { +class BitmapTexture; +class GraphicsContext; + +class CoordinatedSurface : public ThreadSafeRefCounted<CoordinatedSurface> { +public: + enum Flag { + NoFlags = 0, + SupportsAlpha = 1 << 0, + }; + typedef unsigned Flags; + + class Client { + public: + virtual ~Client() { } + virtual void paintToSurfaceContext(GraphicsContext&) = 0; + }; + + typedef RefPtr<CoordinatedSurface> Factory(const IntSize&, Flags); + static void setFactory(Factory); + static RefPtr<CoordinatedSurface> create(const IntSize&, Flags); + + virtual ~CoordinatedSurface() { } + + bool supportsAlpha() const { return flags() & SupportsAlpha; } + IntSize size() const { return m_size; } + + virtual void paintToSurface(const IntRect&, Client&) = 0; + +#if USE(TEXTURE_MAPPER) + virtual void copyToTexture(RefPtr<BitmapTexture>, const IntRect& target, const IntPoint& sourceOffset) = 0; +#endif + +protected: + CoordinatedSurface(const IntSize&, Flags); + Flags flags() const { return m_flags; } + + IntSize m_size; + Flags m_flags; + +private: + static CoordinatedSurface::Factory* s_factory; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) +#endif // CoordinatedSurface_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/SurfaceUpdateInfo.h b/Source/WebCore/platform/graphics/texmap/coordinated/SurfaceUpdateInfo.h new file mode 100644 index 000000000..0e749be93 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/SurfaceUpdateInfo.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef SurfaceUpdateInfo_h +#define SurfaceUpdateInfo_h + +#if USE(COORDINATED_GRAPHICS) + +#include "IntRect.h" + +namespace WebCore { + +class SurfaceUpdateInfo { + +public: + SurfaceUpdateInfo() { } + + // The rect to be updated. + IntRect updateRect; + + // The id of the update atlas including the shareable bitmap containing the updates. + uint32_t atlasID { 0 }; + + // The offset in the bitmap where the rendered contents are. + IntPoint surfaceOffset; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // SurfaceUpdateInfo_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/Tile.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/Tile.cpp new file mode 100644 index 000000000..f155d4433 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/Tile.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" +#include "Tile.h" + +#if USE(COORDINATED_GRAPHICS) +#include "GraphicsContext.h" +#include "SurfaceUpdateInfo.h" +#include "TiledBackingStore.h" +#include "TiledBackingStoreClient.h" + +namespace WebCore { + +static const uint32_t InvalidTileID = 0; + +Tile::Tile(TiledBackingStore& tiledBackingStore, const Coordinate& tileCoordinate) + : m_tiledBackingStore(tiledBackingStore) + , m_coordinate(tileCoordinate) + , m_rect(tiledBackingStore.tileRectForCoordinate(tileCoordinate)) + , m_ID(InvalidTileID) + , m_dirtyRect(m_rect) +{ +} + +Tile::~Tile() +{ + if (m_ID != InvalidTileID) + m_tiledBackingStore.client()->removeTile(m_ID); +} + +bool Tile::isDirty() const +{ + return !m_dirtyRect.isEmpty(); +} + +void Tile::invalidate(const IntRect& dirtyRect) +{ + IntRect tileDirtyRect = intersection(dirtyRect, m_rect); + if (tileDirtyRect.isEmpty()) + return; + + m_dirtyRect.unite(tileDirtyRect); +} + +bool Tile::updateBackBuffer() +{ + if (!isDirty()) + return false; + + SurfaceUpdateInfo updateInfo; + + if (!m_tiledBackingStore.client()->paintToSurface(m_dirtyRect.size(), updateInfo.atlasID, updateInfo.surfaceOffset, *this)) + return false; + + updateInfo.updateRect = m_dirtyRect; + updateInfo.updateRect.move(-m_rect.x(), -m_rect.y()); + + static uint32_t id = 1; + if (m_ID == InvalidTileID) { + m_ID = id++; + // We may get an invalid ID due to wrap-around on overflow. + if (m_ID == InvalidTileID) + m_ID = id++; + m_tiledBackingStore.client()->createTile(m_ID, m_tiledBackingStore.contentsScale()); + } + m_tiledBackingStore.client()->updateTile(m_ID, updateInfo, m_rect); + + m_dirtyRect = IntRect(); + + return true; +} + +void Tile::paintToSurfaceContext(GraphicsContext& context) +{ + context.translate(-m_dirtyRect.x(), -m_dirtyRect.y()); + context.scale(FloatSize(m_tiledBackingStore.contentsScale(), m_tiledBackingStore.contentsScale())); + m_tiledBackingStore.client()->tiledBackingStorePaint(context, m_tiledBackingStore.mapToContents(m_dirtyRect)); +} + +bool Tile::isReadyToPaint() const +{ + return m_ID != InvalidTileID; +} + +void Tile::resize(const IntSize& newSize) +{ + m_rect = IntRect(m_rect.location(), newSize); + m_dirtyRect = m_rect; +} + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/Tile.h b/Source/WebCore/platform/graphics/texmap/coordinated/Tile.h new file mode 100644 index 000000000..0b04d75aa --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/Tile.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 Tile_h +#define Tile_h + +#if USE(COORDINATED_GRAPHICS) +#include "CoordinatedSurface.h" +#include "IntPoint.h" +#include "IntPointHash.h" +#include "IntRect.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class GraphicsContext; +class TiledBackingStore; + +class Tile : public CoordinatedSurface::Client { +public: + typedef IntPoint Coordinate; + + Tile(TiledBackingStore&, const Coordinate&); + ~Tile(); + + bool isDirty() const; + void invalidate(const IntRect&); + bool updateBackBuffer(); + bool isReadyToPaint() const; + + const Coordinate& coordinate() const { return m_coordinate; } + const IntRect& rect() const { return m_rect; } + void resize(const IntSize&); + + void paintToSurfaceContext(GraphicsContext&) override; + +private: + TiledBackingStore& m_tiledBackingStore; + Coordinate m_coordinate; + IntRect m_rect; + + uint32_t m_ID; + IntRect m_dirtyRect; +}; + +} // namespace WebCore + +#endif // USE(COORDINATED_GRAPHICS) + +#endif // Tile_h diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStore.cpp b/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStore.cpp new file mode 100644 index 000000000..b6389165a --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStore.cpp @@ -0,0 +1,425 @@ +/* + Copyright (C) 2010-2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "TiledBackingStore.h" + +#if USE(COORDINATED_GRAPHICS) +#include "GraphicsContext.h" +#include "MemoryPressureHandler.h" +#include "TiledBackingStoreClient.h" +#include <wtf/CheckedArithmetic.h> + +namespace WebCore { + +static const int defaultTileDimension = 512; + +static IntPoint innerBottomRight(const IntRect& rect) +{ + // Actually, the rect does not contain rect.maxX(). Refer to IntRect::contain. + return IntPoint(rect.maxX() - 1, rect.maxY() - 1); +} + +TiledBackingStore::TiledBackingStore(TiledBackingStoreClient* client, float contentsScale) + : m_client(client) + , m_tileSize(defaultTileDimension, defaultTileDimension) + , m_coverAreaMultiplier(2.0f) + , m_contentsScale(contentsScale) + , m_supportsAlpha(false) + , m_pendingTileCreation(false) +{ +} + +TiledBackingStore::~TiledBackingStore() +{ +} + +void TiledBackingStore::setTrajectoryVector(const FloatPoint& trajectoryVector) +{ + m_pendingTrajectoryVector = trajectoryVector; + m_pendingTrajectoryVector.normalize(); +} + +void TiledBackingStore::createTilesIfNeeded(const IntRect& unscaledVisibleRect, const IntRect& contentsRect) +{ + IntRect scaledContentsRect = mapFromContents(contentsRect); + IntRect visibleRect = mapFromContents(unscaledVisibleRect); + float coverAreaMultiplier = MemoryPressureHandler::singleton().isUnderMemoryPressure() ? 1.0f : 2.0f; + + bool didChange = m_trajectoryVector != m_pendingTrajectoryVector || m_visibleRect != visibleRect || m_rect != scaledContentsRect || m_coverAreaMultiplier != coverAreaMultiplier; + if (didChange || m_pendingTileCreation) + createTiles(visibleRect, scaledContentsRect, coverAreaMultiplier); +} + +void TiledBackingStore::invalidate(const IntRect& contentsDirtyRect) +{ + IntRect dirtyRect(mapFromContents(contentsDirtyRect)); + IntRect keepRectFitToTileSize = tileRectForCoordinate(tileCoordinateForPoint(m_keepRect.location())); + keepRectFitToTileSize.unite(tileRectForCoordinate(tileCoordinateForPoint(innerBottomRight(m_keepRect)))); + + // Only iterate on the part of the rect that we know we might have tiles. + IntRect coveredDirtyRect = intersection(dirtyRect, keepRectFitToTileSize); + Tile::Coordinate topLeft = tileCoordinateForPoint(coveredDirtyRect.location()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coveredDirtyRect)); + + for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { + for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { + Tile* currentTile = m_tiles.get(Tile::Coordinate(xCoordinate, yCoordinate)); + if (!currentTile) + continue; + // Pass the full rect to each tile as coveredDirtyRect might not + // contain them completely and we don't want partial tile redraws. + currentTile->invalidate(dirtyRect); + } + } +} + +void TiledBackingStore::updateTileBuffers() +{ + // FIXME: In single threaded case, tile back buffers could be updated asynchronously + // one by one and then swapped to front in one go. This would minimize the time spent + // blocking on tile updates. + bool updated = false; + for (auto& tile : m_tiles.values()) { + if (!tile->isDirty()) + continue; + + updated |= tile->updateBackBuffer(); + } + + if (updated) + m_client->didUpdateTileBuffers(); +} + +double TiledBackingStore::tileDistance(const IntRect& viewport, const Tile::Coordinate& tileCoordinate) const +{ + if (viewport.intersects(tileRectForCoordinate(tileCoordinate))) + return 0; + + IntPoint viewCenter = viewport.location() + IntSize(viewport.width() / 2, viewport.height() / 2); + Tile::Coordinate centerCoordinate = tileCoordinateForPoint(viewCenter); + + return std::max(abs(centerCoordinate.y() - tileCoordinate.y()), abs(centerCoordinate.x() - tileCoordinate.x())); +} + +// Returns a ratio between 0.0f and 1.0f of the surface covered by rendered tiles. +float TiledBackingStore::coverageRatio(const WebCore::IntRect& dirtyRect) const +{ + float rectArea = dirtyRect.width() * dirtyRect.height(); + float coverArea = 0.0f; + + Tile::Coordinate topLeft = tileCoordinateForPoint(dirtyRect.location()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(dirtyRect)); + + for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { + for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { + Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); + Tile* currentTile = m_tiles.get(currentCoordinate); + if (currentTile && currentTile->isReadyToPaint()) { + IntRect coverRect = intersection(dirtyRect, currentTile->rect()); + coverArea += coverRect.width() * coverRect.height(); + } + } + } + return coverArea / rectArea; +} + +bool TiledBackingStore::visibleAreaIsCovered() const +{ + return coverageRatio(intersection(m_visibleRect, m_rect)) == 1.0f; +} + +void TiledBackingStore::createTiles(const IntRect& visibleRect, const IntRect& scaledContentsRect, float coverAreaMultiplier) +{ + // Update our backing store geometry. + const IntRect previousRect = m_rect; + m_rect = scaledContentsRect; + m_trajectoryVector = m_pendingTrajectoryVector; + m_visibleRect = visibleRect; + m_coverAreaMultiplier = coverAreaMultiplier; + + if (m_rect.isEmpty()) { + setCoverRect(IntRect()); + setKeepRect(IntRect()); + return; + } + + /* We must compute cover and keep rects using the visibleRect, instead of the rect intersecting the visibleRect with m_rect, + * because TBS can be used as a backing store of GraphicsLayer and the visible rect usually does not intersect with m_rect. + * In the below case, the intersecting rect is an empty. + * + * +---------------+ + * | | + * | m_rect | + * | +-------|-----------------------+ + * | | HERE | cover or keep | + * +---------------+ rect | + * | +---------+ | + * | | visible | | + * | | rect | | + * | +---------+ | + * | | + * | | + * +-------------------------------+ + * + * We must create or keep the tiles in the HERE region. + */ + + IntRect coverRect; + IntRect keepRect; + computeCoverAndKeepRect(m_visibleRect, coverRect, keepRect); + + setCoverRect(coverRect); + setKeepRect(keepRect); + + if (coverRect.isEmpty()) + return; + + // Resize tiles at the edge in case the contents size has changed, but only do so + // after having dropped tiles outside the keep rect. + bool didResizeTiles = false; + if (previousRect != m_rect) + didResizeTiles = resizeEdgeTiles(); + + // Search for the tile position closest to the viewport center that does not yet contain a tile. + // Which position is considered the closest depends on the tileDistance function. + double shortestDistance = std::numeric_limits<double>::infinity(); + Vector<Tile::Coordinate> tilesToCreate; + unsigned requiredTileCount = 0; + + // Cover areas (in tiles) with minimum distance from the visible rect. If the visible rect is + // not covered already it will be covered first in one go, due to the distance being 0 for tiles + // inside the visible rect. + Tile::Coordinate topLeft = tileCoordinateForPoint(coverRect.location()); + Tile::Coordinate bottomRight = tileCoordinateForPoint(innerBottomRight(coverRect)); + for (int yCoordinate = topLeft.y(); yCoordinate <= bottomRight.y(); ++yCoordinate) { + for (int xCoordinate = topLeft.x(); xCoordinate <= bottomRight.x(); ++xCoordinate) { + Tile::Coordinate currentCoordinate(xCoordinate, yCoordinate); + if (m_tiles.contains(currentCoordinate)) + continue; + ++requiredTileCount; + double distance = tileDistance(m_visibleRect, currentCoordinate); + if (distance > shortestDistance) + continue; + if (distance < shortestDistance) { + tilesToCreate.clear(); + shortestDistance = distance; + } + tilesToCreate.append(currentCoordinate); + } + } + + // Now construct the tile(s) within the shortest distance. + unsigned tilesToCreateCount = tilesToCreate.size(); + for (unsigned n = 0; n < tilesToCreateCount; ++n) { + Tile::Coordinate coordinate = tilesToCreate[n]; + m_tiles.add(coordinate, std::make_unique<Tile>(*this, coordinate)); + } + requiredTileCount -= tilesToCreateCount; + + // Paint the content of the newly created tiles or resized tiles. + if (tilesToCreateCount || didResizeTiles) + updateTileBuffers(); + + // Re-call createTiles on a timer to cover the visible area with the newest shortest distance. + m_pendingTileCreation = requiredTileCount; + if (m_pendingTileCreation) + m_client->tiledBackingStoreHasPendingTileCreation(); +} + +void TiledBackingStore::adjustForContentsRect(IntRect& rect) const +{ + IntRect bounds = m_rect; + IntSize candidateSize = rect.size(); + + rect.intersect(bounds); + + if (rect.size() == candidateSize) + return; + + /* + * In the following case, there is no intersection of the contents rect and the cover rect. + * Thus the latter should not be inflated. + * + * +---------------+ + * | m_rect | + * +---------------+ + * + * +-------------------------------+ + * | cover rect | + * | +---------+ | + * | | visible | | + * | | rect | | + * | +---------+ | + * +-------------------------------+ + */ + if (rect.isEmpty()) + return; + + // Try to create a cover rect of the same size as the candidate, but within content bounds. + int pixelsCovered = 0; + if (!WTF::safeMultiply(candidateSize.width(), candidateSize.height(), pixelsCovered)) + pixelsCovered = std::numeric_limits<int>::max(); + + if (rect.width() < candidateSize.width()) + rect.inflateY(((pixelsCovered / rect.width()) - rect.height()) / 2); + if (rect.height() < candidateSize.height()) + rect.inflateX(((pixelsCovered / rect.height()) - rect.width()) / 2); + + rect.intersect(bounds); +} + +void TiledBackingStore::computeCoverAndKeepRect(const IntRect& visibleRect, IntRect& coverRect, IntRect& keepRect) const +{ + coverRect = visibleRect; + keepRect = visibleRect; + + // If we cover more that the actual viewport we can be smart about which tiles we choose to render. + if (m_coverAreaMultiplier > 1) { + // The initial cover area covers equally in each direction, according to the coverAreaMultiplier. + coverRect.inflateX(visibleRect.width() * (m_coverAreaMultiplier - 1) / 2); + coverRect.inflateY(visibleRect.height() * (m_coverAreaMultiplier - 1) / 2); + keepRect = coverRect; + + if (m_trajectoryVector != FloatPoint::zero()) { + // A null trajectory vector (no motion) means that tiles for the coverArea will be created. + // A non-null trajectory vector will shrink the covered rect to visibleRect plus its expansion from its + // center toward the cover area edges in the direction of the given vector. + + // E.g. if visibleRect == (10,10)5x5 and coverAreaMultiplier == 3.0: + // a (0,0) trajectory vector will create tiles intersecting (5,5)15x15, + // a (1,0) trajectory vector will create tiles intersecting (10,10)10x5, + // and a (1,1) trajectory vector will create tiles intersecting (10,10)10x10. + + // Multiply the vector by the distance to the edge of the cover area. + float trajectoryVectorMultiplier = (m_coverAreaMultiplier - 1) / 2; + + // Unite the visible rect with a "ghost" of the visible rect moved in the direction of the trajectory vector. + coverRect = visibleRect; + coverRect.move(coverRect.width() * m_trajectoryVector.x() * trajectoryVectorMultiplier, coverRect.height() * m_trajectoryVector.y() * trajectoryVectorMultiplier); + + coverRect.unite(visibleRect); + } + ASSERT(keepRect.contains(coverRect)); + } + + adjustForContentsRect(coverRect); + + // The keep rect is an inflated version of the cover rect, inflated in tile dimensions. + keepRect.unite(coverRect); + keepRect.inflateX(m_tileSize.width() / 2); + keepRect.inflateY(m_tileSize.height() / 2); + keepRect.intersect(m_rect); + + ASSERT(coverRect.isEmpty() || keepRect.contains(coverRect)); +} + +bool TiledBackingStore::resizeEdgeTiles() +{ + bool wasResized = false; + Vector<Tile::Coordinate> tilesToRemove; + for (auto& tile : m_tiles.values()) { + Tile::Coordinate tileCoordinate = tile->coordinate(); + IntRect tileRect = tile->rect(); + IntRect expectedTileRect = tileRectForCoordinate(tileCoordinate); + if (expectedTileRect.isEmpty()) + tilesToRemove.append(tileCoordinate); + else if (expectedTileRect != tileRect) { + tile->resize(expectedTileRect.size()); + wasResized = true; + } + } + + for (auto& coordinateToRemove : tilesToRemove) + m_tiles.remove(coordinateToRemove); + + return wasResized; +} + +void TiledBackingStore::setKeepRect(const IntRect& keepRect) +{ + // Drop tiles outside the new keepRect. + + FloatRect keepRectF = keepRect; + + Vector<Tile::Coordinate> toRemove; + for (auto& tile : m_tiles.values()) { + Tile::Coordinate coordinate = tile->coordinate(); + FloatRect tileRect = tile->rect(); + if (!tileRect.intersects(keepRectF)) + toRemove.append(coordinate); + } + + for (auto& coordinateToRemove : toRemove) + m_tiles.remove(coordinateToRemove); + + m_keepRect = keepRect; +} + +void TiledBackingStore::removeAllNonVisibleTiles(const IntRect& unscaledVisibleRect, const IntRect& contentsRect) +{ + IntRect boundedVisibleRect = mapFromContents(intersection(unscaledVisibleRect, contentsRect)); + setKeepRect(boundedVisibleRect); +} + +IntRect TiledBackingStore::mapToContents(const IntRect& rect) const +{ + return enclosingIntRect(FloatRect(rect.x() / m_contentsScale, + rect.y() / m_contentsScale, + rect.width() / m_contentsScale, + rect.height() / m_contentsScale)); +} + +IntRect TiledBackingStore::mapFromContents(const IntRect& rect) const +{ + return enclosingIntRect(FloatRect(rect.x() * m_contentsScale, + rect.y() * m_contentsScale, + rect.width() * m_contentsScale, + rect.height() * m_contentsScale)); +} + +IntRect TiledBackingStore::tileRectForCoordinate(const Tile::Coordinate& coordinate) const +{ + IntRect rect(coordinate.x() * m_tileSize.width(), + coordinate.y() * m_tileSize.height(), + m_tileSize.width(), + m_tileSize.height()); + + rect.intersect(m_rect); + return rect; +} + +Tile::Coordinate TiledBackingStore::tileCoordinateForPoint(const IntPoint& point) const +{ + int x = point.x() / m_tileSize.width(); + int y = point.y() / m_tileSize.height(); + return Tile::Coordinate(std::max(x, 0), std::max(y, 0)); +} + +void TiledBackingStore::setSupportsAlpha(bool a) +{ + if (a == m_supportsAlpha) + return; + m_supportsAlpha = a; + invalidate(m_rect); +} + +} + +#endif diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStore.h b/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStore.h new file mode 100644 index 000000000..c17f7644d --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStore.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2010-2012 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TiledBackingStore_h +#define TiledBackingStore_h + +#if USE(COORDINATED_GRAPHICS) + +#include "FloatPoint.h" +#include "IntPoint.h" +#include "IntRect.h" +#include "Tile.h" +#include "Timer.h" +#include <wtf/Assertions.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +class GraphicsContext; +class TiledBackingStoreClient; + +class TiledBackingStore { + WTF_MAKE_NONCOPYABLE(TiledBackingStore); WTF_MAKE_FAST_ALLOCATED; +public: + TiledBackingStore(TiledBackingStoreClient*, float contentsScale = 1.f); + ~TiledBackingStore(); + + TiledBackingStoreClient* client() { return m_client; } + + void setTrajectoryVector(const FloatPoint&); + void createTilesIfNeeded(const IntRect& unscaledVisibleRect, const IntRect& contentsRect); + + float contentsScale() { return m_contentsScale; } + + void updateTileBuffers(); + + void invalidate(const IntRect& dirtyRect); + + IntRect mapToContents(const IntRect&) const; + IntRect mapFromContents(const IntRect&) const; + + IntRect tileRectForCoordinate(const Tile::Coordinate&) const; + Tile::Coordinate tileCoordinateForPoint(const IntPoint&) const; + double tileDistance(const IntRect& viewport, const Tile::Coordinate&) const; + + IntRect coverRect() const { return m_coverRect; } + bool visibleAreaIsCovered() const; + void removeAllNonVisibleTiles(const IntRect& unscaledVisibleRect, const IntRect& contentsRect); + + void setSupportsAlpha(bool); + +private: + void createTiles(const IntRect& visibleRect, const IntRect& scaledContentsRect, float coverAreaMultiplier); + void computeCoverAndKeepRect(const IntRect& visibleRect, IntRect& coverRect, IntRect& keepRect) const; + + bool resizeEdgeTiles(); + void setCoverRect(const IntRect& rect) { m_coverRect = rect; } + void setKeepRect(const IntRect&); + + float coverageRatio(const IntRect&) const; + void adjustForContentsRect(IntRect&) const; + + void paintCheckerPattern(GraphicsContext*, const IntRect&, const Tile::Coordinate&); + +private: + TiledBackingStoreClient* m_client; + + typedef HashMap<Tile::Coordinate, std::unique_ptr<Tile>> TileMap; + TileMap m_tiles; + + IntSize m_tileSize; + float m_coverAreaMultiplier; + + FloatPoint m_trajectoryVector; + FloatPoint m_pendingTrajectoryVector; + IntRect m_visibleRect; + + IntRect m_coverRect; + IntRect m_keepRect; + IntRect m_rect; + + float m_contentsScale; + + bool m_supportsAlpha; + bool m_pendingTileCreation; + + friend class Tile; +}; + +} + +#endif +#endif diff --git a/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStoreClient.h b/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStoreClient.h new file mode 100644 index 000000000..61936ff9c --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/coordinated/TiledBackingStoreClient.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TiledBackingStoreClient_h +#define TiledBackingStoreClient_h + +#include "CoordinatedSurface.h" + +namespace WebCore { + +#if USE(COORDINATED_GRAPHICS) + +class GraphicsContext; +class SurfaceUpdateInfo; + +class TiledBackingStoreClient { +public: + virtual ~TiledBackingStoreClient() { } + virtual void tiledBackingStorePaint(GraphicsContext&, const IntRect&) = 0; + virtual void didUpdateTileBuffers() = 0; + virtual void tiledBackingStoreHasPendingTileCreation() = 0; + + virtual void createTile(uint32_t tileID, float) = 0; + virtual void updateTile(uint32_t tileID, const SurfaceUpdateInfo&, const IntRect&) = 0; + virtual void removeTile(uint32_t tileID) = 0; + virtual bool paintToSurface(const IntSize&, uint32_t& atlasID, IntPoint&, CoordinatedSurface::Client&) = 0; +}; + +#endif + +} + +#endif |