db517cad2633b8bf4e7154b574822572c46590aa
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / Canvas2DLayerBridge.cpp
1 /*
2  * Copyright (C) 2012 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
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #include "Canvas2DLayerBridge.h"
29
30 #include "GrContext.h"
31 #include "GraphicsContext3D.h"
32 #include "GraphicsContext3DPrivate.h"
33 #include "LayerRendererChromium.h" // For GLC() macro.
34 #include "TraceEvent.h"
35 #include <public/WebCompositor.h>
36 #include <public/WebGraphicsContext3D.h>
37
38 using WebKit::WebExternalTextureLayer;
39 using WebKit::WebGraphicsContext3D;
40 using WebKit::WebTextureUpdater;
41
42 namespace WebCore {
43
44 Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, const IntSize& size, DeferralMode deferralMode, unsigned textureId)
45     : m_deferralMode(deferralMode)
46     // FIXME: We currently turn off double buffering when canvas rendering is
47     // deferred. What we should be doing is to use a smarter heuristic based
48     // on GPU resource monitoring and other factors to chose between single
49     // and double buffering.
50     , m_useDoubleBuffering(WebKit::WebCompositor::threadingEnabled() && deferralMode == NonDeferred)
51     , m_frontBufferTexture(0)
52     , m_backBufferTexture(textureId)
53     , m_size(size)
54     , m_canvas(0)
55     , m_context(context)
56 {
57     if (m_useDoubleBuffering) {
58         m_context->makeContextCurrent();
59         GLC(m_context.get(), m_frontBufferTexture = m_context->createTexture());
60         GLC(m_context.get(), m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_frontBufferTexture));
61         // Do basic linear filtering on resize.
62         GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
63         GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
64         // NPOT textures in GL ES only work when the wrap mode is set to GraphicsContext3D::CLAMP_TO_EDGE.
65         GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
66         GLC(m_context.get(), m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
67         GLC(m_context.get(), m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, size.width(), size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE));
68         if (GrContext* grContext = m_context->grContext())
69             grContext->resetContext();
70     }
71
72     m_layer = WebExternalTextureLayer::create(this);
73     m_layer.setTextureId(textureId);
74     m_layer.setRateLimitContext(!WebKit::WebCompositor::threadingEnabled() || m_useDoubleBuffering);
75 }
76
77 Canvas2DLayerBridge::~Canvas2DLayerBridge()
78 {
79     if (SkDeferredCanvas* deferred = deferredCanvas())
80         deferred->setNotificationClient(0);
81     m_layer.setTextureId(0);
82     if (m_useDoubleBuffering) {
83         m_context->makeContextCurrent();
84         GLC(m_context.get(), m_context->deleteTexture(m_frontBufferTexture));
85         m_context->flush();
86     }
87     m_layer.clearClient();
88 }
89
90 SkDeferredCanvas* Canvas2DLayerBridge::deferredCanvas()
91 {
92     if (m_deferralMode == Deferred)
93         return static_cast<SkDeferredCanvas*>(m_canvas);
94     return 0;
95 }
96
97 void Canvas2DLayerBridge::prepareForDraw()
98 {
99     ASSERT(deferredCanvas());
100     if (!m_useDoubleBuffering)
101         m_layer.willModifyTexture();
102     m_context->makeContextCurrent();
103 }
104
105 SkCanvas* Canvas2DLayerBridge::skCanvas(SkDevice* device)
106 {
107     ASSERT(!m_canvas);
108     if (m_deferralMode == Deferred) {
109         SkDeferredCanvas* deferred = new SkDeferredCanvas(device);
110         deferred->setNotificationClient(this);
111         m_canvas = deferred;
112     } else
113         m_canvas = new SkCanvas(device);
114
115     return m_canvas;
116 }
117
118
119 unsigned Canvas2DLayerBridge::prepareTexture(WebTextureUpdater& updater)
120 {
121     m_context->makeContextCurrent();
122
123     if (m_canvas) {
124         TRACE_EVENT0("cc", "Canvas2DLayerBridge::SkCanvas::flush");
125         m_canvas->flush();
126     }
127
128     m_context->flush();
129
130     if (m_useDoubleBuffering) {
131         updater.appendCopy(m_backBufferTexture, m_frontBufferTexture, m_size);
132         return m_frontBufferTexture;
133     }
134
135     if (m_canvas) {
136         // Notify skia that the state of the backing store texture object will be touched by the compositor
137         GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->getDevice()->accessRenderTarget());
138         if (renderTarget)
139             renderTarget->asTexture()->invalidateCachedState();
140     }
141     return m_backBufferTexture;
142 }
143
144 WebGraphicsContext3D* Canvas2DLayerBridge::context()
145 {
146     return GraphicsContext3DPrivate::extractWebGraphicsContext3D(m_context.get());
147 }
148
149 WebKit::WebLayer* Canvas2DLayerBridge::layer()
150 {
151     return &m_layer;
152 }
153
154 void Canvas2DLayerBridge::contextAcquired()
155 {
156     if (m_deferralMode == NonDeferred && !m_useDoubleBuffering)
157         m_layer.willModifyTexture();
158 }
159
160 unsigned Canvas2DLayerBridge::backBufferTexture()
161 {
162     contextAcquired();
163     if (m_canvas)
164         m_canvas->flush();
165     m_context->flush();
166     return m_backBufferTexture;
167 }
168
169 }
170