/* * Copyright (C) 2011, 2012 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" #if ENABLE(GRAPHICS_CONTEXT_3D) #include "GraphicsContext3DPrivate.h" #include "HostWindow.h" #include "NotImplemented.h" #include #if USE(CAIRO) #include "PlatformContextCairo.h" #endif #if USE(OPENGL_ES_2) #include #include #else #include "OpenGLShims.h" #endif #if USE(TEXTURE_MAPPER_GL) #include #endif #if USE(COORDINATED_GRAPHICS_THREADED) #include "TextureMapperPlatformLayerBuffer.h" #endif using namespace std; namespace WebCore { GraphicsContext3DPrivate::GraphicsContext3DPrivate(GraphicsContext3D* context, GraphicsContext3D::RenderStyle renderStyle) : m_context(context) , m_renderStyle(renderStyle) { switch (renderStyle) { case GraphicsContext3D::RenderOffscreen: m_glContext = GLContext::createOffscreenContext(GLContext::sharingContext()); 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 } GraphicsContext3DPrivate::~GraphicsContext3DPrivate() { #if USE(TEXTURE_MAPPER) && !USE(COORDINATED_GRAPHICS_THREADED) if (client()) client()->platformLayerWillBeDestroyed(); #endif } bool GraphicsContext3DPrivate::makeContextCurrent() { return m_glContext ? m_glContext->makeContextCurrent() : false; } PlatformGraphicsContext3D GraphicsContext3DPrivate::platformContext() { return m_glContext ? m_glContext->platformContext() : GLContext::getCurrent()->platformContext(); } #if USE(COORDINATED_GRAPHICS_THREADED) RefPtr GraphicsContext3DPrivate::proxy() const { return m_platformLayerProxy.copyRef(); } void GraphicsContext3DPrivate::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(m_context->m_compositorTexture, textureSize, flags)); } m_context->markLayerComposited(); } #elif USE(TEXTURE_MAPPER) void GraphicsContext3DPrivate::paintToTextureMapper(TextureMapper& textureMapper, const FloatRect& targetRect, const TransformationMatrix& matrix, float opacity) { if (!m_glContext) return; ASSERT(m_renderStyle == GraphicsContext3D::RenderOffscreen); m_context->markLayerComposited(); // FIXME: We do not support mask for the moment with TextureMapperImageBuffer. if (textureMapper->accelerationMode() != TextureMapper::OpenGLMode) { GraphicsContext* context = textureMapper->graphicsContext(); context->save(); context->platformContext()->setGlobalAlpha(opacity); const int height = m_context->m_currentHeight; const int width = m_context->m_currentWidth; int totalBytes = width * height * 4; auto pixels = std::make_unique(totalBytes); if (!pixels) return; // OpenGL keeps the pixels stored bottom up, so we need to flip the image here. context->translate(0, height); context->scale(FloatSize(1, -1)); context->concatCTM(matrix.toAffineTransform()); m_context->readRenderingResults(pixels.get(), totalBytes); // Premultiply alpha. for (int i = 0; i < totalBytes; i += 4) if (pixels[i + 3] != 255) { pixels[i + 0] = min(255, pixels[i + 0] * pixels[i + 3] / 255); pixels[i + 1] = min(255, pixels[i + 1] * pixels[i + 3] / 255); pixels[i + 2] = min(255, pixels[i + 2] * pixels[i + 3] / 255); } RefPtr imageSurface = adoptRef(cairo_image_surface_create_for_data( const_cast(pixels.get()), CAIRO_FORMAT_ARGB32, width, height, width * 4)); context->platformContext()->drawSurfaceToContext(imageSurface.get(), targetRect, IntRect(0, 0, width, height), context); context->restore(); return; } #if USE(TEXTURE_MAPPER_GL) if (m_context->m_attrs.antialias && m_context->m_state.boundFBO == m_context->m_multisampleFBO) { GLContext* previousActiveContext = GLContext::getCurrent(); 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(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(TEXTURE_MAPPER) } // namespace WebCore #endif // ENABLE(GRAPHICS_CONTEXT_3D)