1 /* 2 * Copyright (c) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include "DrawingBuffer.h" 34 35 #include "Extensions3DChromium.h" 36 #include "GraphicsContext3D.h" 37 #include "SharedGraphicsContext3D.h" 38 39 #if ENABLE(SKIA_GPU) 40 #include "GrContext.h" 41 #endif 42 43 #if USE(ACCELERATED_COMPOSITING) 44 #include "Canvas2DLayerChromium.h" 45 #endif 46 47 namespace WebCore { 48 49 struct DrawingBufferInternal { 50 unsigned offscreenColorTexture; 51 #if USE(ACCELERATED_COMPOSITING) 52 RefPtr<Canvas2DLayerChromium> platformLayer; 53 #endif 54 }; 55 56 static unsigned generateColorTexture(GraphicsContext3D* context, const IntSize& size) 57 { 58 unsigned offscreenColorTexture = context->createTexture(); 59 if (!offscreenColorTexture) 60 return 0; 61 62 context->bindTexture(GraphicsContext3D::TEXTURE_2D, offscreenColorTexture); 63 context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::NEAREST); 64 context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST); 65 context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE); 66 context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE); 67 context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE); 68 context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, offscreenColorTexture, 0); 69 70 return offscreenColorTexture; 71 } 72 73 74 DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, 75 const IntSize& size, 76 bool multisampleExtensionSupported, 77 bool packedDepthStencilExtensionSupported) 78 : m_context(context) 79 , m_size(-1, -1) 80 , m_multisampleExtensionSupported(multisampleExtensionSupported) 81 , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) 82 , m_fbo(0) 83 , m_colorBuffer(0) 84 , m_depthStencilBuffer(0) 85 , m_depthBuffer(0) 86 , m_stencilBuffer(0) 87 , m_multisampleFBO(0) 88 , m_multisampleColorBuffer(0) 89 , m_internal(new DrawingBufferInternal) 90 #if ENABLE(SKIA_GPU) 91 , m_grContext(0) 92 #endif 93 { 94 if (!m_context->getExtensions()->supports("GL_CHROMIUM_copy_texture_to_parent_texture")) { 95 m_context.clear(); 96 return; 97 } 98 m_fbo = context->createFramebuffer(); 99 context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); 100 m_colorBuffer = generateColorTexture(context, size); 101 createSecondaryBuffers(); 102 reset(size); 103 } 104 105 DrawingBuffer::~DrawingBuffer() 106 { 107 #if USE(ACCELERATED_COMPOSITING) 108 if (m_internal->platformLayer) 109 m_internal->platformLayer->setDrawingBuffer(0); 110 #endif 111 112 if (!m_context) 113 return; 114 115 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); 116 m_context->deleteTexture(m_colorBuffer); 117 118 clear(); 119 } 120 121 #if USE(ACCELERATED_COMPOSITING) 122 void DrawingBuffer::publishToPlatformLayer() 123 { 124 if (!m_context) 125 return; 126 127 if (m_callback) 128 m_callback->willPublish(); 129 if (multisample()) 130 commit(); 131 unsigned parentTexture = m_internal->platformLayer->textureId(); 132 // FIXME: We do the copy in the canvas' (child) context so that it executes in the correct order relative to 133 // other commands in the child context. This ensures that the parent texture always contains a complete 134 // frame and not some intermediate result. However, there is no synchronization to ensure that this copy 135 // happens before the compositor draws. This means we might draw stale frames sometimes. Ideally this 136 // would insert a fence into the child command stream that the compositor could wait for. 137 m_context->makeContextCurrent(); 138 #if ENABLE(SKIA_GPU) 139 if (m_grContext) 140 m_grContext->flush(0); 141 #endif 142 static_cast<Extensions3DChromium*>(m_context->getExtensions())->copyTextureToParentTextureCHROMIUM(m_colorBuffer, parentTexture); 143 m_context->flush(); 144 } 145 #endif 146 147 void DrawingBuffer::didReset() 148 { 149 #if USE(ACCELERATED_COMPOSITING) 150 if (m_internal->platformLayer) 151 m_internal->platformLayer->setTextureChanged(); 152 #endif 153 } 154 155 #if USE(ACCELERATED_COMPOSITING) 156 PlatformLayer* DrawingBuffer::platformLayer() 157 { 158 if (!m_internal->platformLayer) 159 m_internal->platformLayer = Canvas2DLayerChromium::create(this, 0); 160 return m_internal->platformLayer.get(); 161 } 162 #endif 163 164 Platform3DObject DrawingBuffer::platformColorBuffer() const 165 { 166 return m_colorBuffer; 167 } 168 169 #if ENABLE(SKIA_GPU) 170 void DrawingBuffer::setGrContext(GrContext* context) 171 { 172 // We just take a ptr without referencing it, as we require that we never outlive 173 // the SharedGraphicsContext3D object that is giving us the context. 174 m_grContext = context; 175 } 176 177 void DrawingBuffer::getGrPlatformSurfaceDesc(GrPlatformSurfaceDesc* desc) 178 { 179 desc->fSurfaceType = kTextureRenderTarget_GrPlatformSurfaceType; 180 181 desc->fPlatformTexture = m_colorBuffer; 182 if (multisample()) { 183 desc->fRenderTargetFlags = kIsMultisampled_GrPlatformRenderTargetFlagBit | kGrCanResolve_GrPlatformRenderTargetFlagBit; 184 desc->fPlatformRenderTarget = m_multisampleFBO; 185 desc->fPlatformResolveDestination = m_fbo; 186 } else { 187 desc->fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; 188 desc->fPlatformRenderTarget = m_fbo; 189 desc->fPlatformResolveDestination = 0; 190 } 191 192 desc->fWidth = m_size.width(); 193 desc->fHeight = m_size.height(); 194 desc->fConfig = kRGBA_8888_GrPixelConfig; 195 196 desc->fStencilBits = (m_depthStencilBuffer || m_stencilBuffer) ? 8 : 0; 197 } 198 199 #endif 200 201 } 202