Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1256)

Side by Side Diff: Source/core/platform/graphics/Canvas2DLayerBridge.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "core/platform/graphics/Canvas2DLayerBridge.h"
29
30 #include "GrContext.h"
31 #include "SkDevice.h"
32 #include "SkSurface.h"
33 #include "core/platform/graphics/Canvas2DLayerManager.h"
34 #include "core/platform/graphics/GraphicsLayer.h"
35 #include "core/platform/graphics/gpu/SharedGraphicsContext3D.h"
36 #include "platform/TraceEvent.h"
37 #include "public/platform/Platform.h"
38 #include "public/platform/WebCompositorSupport.h"
39 #include "public/platform/WebGraphicsContext3D.h"
40
41 using blink::WebExternalTextureLayer;
42 using blink::WebGraphicsContext3D;
43
44 namespace WebCore {
45
46 void Canvas2DLayerBridgePtr::clear()
47 {
48 if (m_ptr) {
49 m_ptr->destroy();
50 m_ptr.clear();
51 }
52 }
53
54 Canvas2DLayerBridgePtr& Canvas2DLayerBridgePtr::operator=(const PassRefPtr<Canva s2DLayerBridge>& other)
55 {
56 clear();
57 m_ptr = other;
58 return *this;
59 }
60
61 static SkSurface* createSurface(GraphicsContext3D* context3D, const IntSize& siz e, int msaaSampleCount)
62 {
63 ASSERT(!context3D->webContext()->isContextLost());
64 GrContext* gr = context3D->grContext();
65 if (!gr)
66 return 0;
67 gr->resetContext();
68 SkImageInfo info;
69 info.fWidth = size.width();
70 info.fHeight = size.height();
71 info.fColorType = kPMColor_SkColorType;
72 info.fAlphaType = kPremul_SkAlphaType;
73 return SkSurface::NewRenderTarget(gr, info, msaaSampleCount);
74 }
75
76 PassRefPtr<Canvas2DLayerBridge> Canvas2DLayerBridge::create(PassRefPtr<GraphicsC ontext3D> context, const IntSize& size, OpacityMode opacityMode, int msaaSampleC ount)
77 {
78 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation");
79 SkAutoTUnref<SkSurface> surface(createSurface(context.get(), size, msaaSampl eCount));
80 if (!surface.get()) {
81 return PassRefPtr<Canvas2DLayerBridge>();
82 }
83 RefPtr<SkDeferredCanvas> canvas = adoptRef(SkDeferredCanvas::Create(surface. get()));
84 RefPtr<Canvas2DLayerBridge> layerBridge = adoptRef(new Canvas2DLayerBridge(c ontext, canvas.release(), msaaSampleCount, opacityMode));
85 return layerBridge.release();
86 }
87
88 Canvas2DLayerBridge::Canvas2DLayerBridge(PassRefPtr<GraphicsContext3D> context, PassRefPtr<SkDeferredCanvas> canvas, int msaaSampleCount, OpacityMode opacityMod e)
89 : m_canvas(canvas)
90 , m_context(context)
91 , m_msaaSampleCount(msaaSampleCount)
92 , m_bytesAllocated(0)
93 , m_didRecordDrawCommand(false)
94 , m_surfaceIsValid(true)
95 , m_framesPending(0)
96 , m_destructionInProgress(false)
97 , m_rateLimitingEnabled(false)
98 , m_next(0)
99 , m_prev(0)
100 , m_lastImageId(0)
101 {
102 ASSERT(m_canvas);
103 // Used by browser tests to detect the use of a Canvas2DLayerBridge.
104 TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation");
105 m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createEx ternalTextureLayer(this));
106 m_layer->setOpaque(opacityMode == Opaque);
107 m_layer->setBlendBackgroundColor(opacityMode != Opaque);
108 GraphicsLayer::registerContentsLayer(m_layer->layer());
109 m_layer->setRateLimitContext(m_rateLimitingEnabled);
110 m_canvas->setNotificationClient(this);
111 }
112
113 Canvas2DLayerBridge::~Canvas2DLayerBridge()
114 {
115 ASSERT(m_destructionInProgress);
116 m_layer.clear();
117 Vector<MailboxInfo>::iterator mailboxInfo;
118 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mai lboxInfo++) {
119 ASSERT(mailboxInfo->m_status != MailboxInUse);
120 if (mailboxInfo->m_status == MailboxReleased) {
121 if (mailboxInfo->m_mailbox.syncPoint) {
122 context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint);
123 mailboxInfo->m_mailbox.syncPoint = 0;
124 }
125 // Invalidate texture state in case the compositor altered it since the copy-on-write.
126 mailboxInfo->m_image->getTexture()->invalidateCachedState();
127 }
128 }
129 m_mailboxes.clear();
130 }
131
132 void Canvas2DLayerBridge::destroy()
133 {
134 ASSERT(!m_destructionInProgress);
135 m_destructionInProgress = true;
136 GraphicsLayer::unregisterContentsLayer(m_layer->layer());
137 m_canvas->setNotificationClient(0);
138 m_layer->clearTexture();
139 Canvas2DLayerManager::get().layerToBeDestroyed(this);
140 // Orphaning the layer is required to trigger the recration of a new layer
141 // in the case where destruction is caused by a canvas resize. Test:
142 // virtual/gpu/fast/canvas/canvas-resize-after-paint-without-layout.html
143 m_layer->layer()->removeFromParent();
144 }
145
146 void Canvas2DLayerBridge::limitPendingFrames()
147 {
148 ASSERT(!m_destructionInProgress);
149 if (m_didRecordDrawCommand) {
150 m_framesPending++;
151 m_didRecordDrawCommand = false;
152 if (m_framesPending > 1) {
153 // Turn on the rate limiter if this layer tends to accumulate a
154 // non-discardable multi-frame backlog of draw commands.
155 setRateLimitingEnabled(true);
156 }
157 if (m_rateLimitingEnabled) {
158 flush();
159 }
160 }
161 }
162
163 void Canvas2DLayerBridge::prepareForDraw()
164 {
165 ASSERT(!m_destructionInProgress);
166 ASSERT(m_layer);
167 if (!isValid()) {
168 if (m_canvas) {
169 // drop pending commands because there is no surface to draw to
170 m_canvas->silentFlush();
171 }
172 return;
173 }
174 m_context->makeContextCurrent();
175 }
176
177 void Canvas2DLayerBridge::storageAllocatedForRecordingChanged(size_t bytesAlloca ted)
178 {
179 ASSERT(!m_destructionInProgress);
180 intptr_t delta = (intptr_t)bytesAllocated - (intptr_t)m_bytesAllocated;
181 m_bytesAllocated = bytesAllocated;
182 Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, delta);
183 }
184
185 size_t Canvas2DLayerBridge::storageAllocatedForRecording()
186 {
187 ASSERT(!m_destructionInProgress);
188 return m_canvas->storageAllocatedForRecording();
189 }
190
191 void Canvas2DLayerBridge::flushedDrawCommands()
192 {
193 ASSERT(!m_destructionInProgress);
194 storageAllocatedForRecordingChanged(storageAllocatedForRecording());
195 m_framesPending = 0;
196 }
197
198 void Canvas2DLayerBridge::skippedPendingDrawCommands()
199 {
200 ASSERT(!m_destructionInProgress);
201 // Stop triggering the rate limiter if SkDeferredCanvas is detecting
202 // and optimizing overdraw.
203 setRateLimitingEnabled(false);
204 flushedDrawCommands();
205 }
206
207 void Canvas2DLayerBridge::setRateLimitingEnabled(bool enabled)
208 {
209 ASSERT(!m_destructionInProgress || !enabled);
210 if (m_rateLimitingEnabled != enabled) {
211 m_rateLimitingEnabled = enabled;
212 m_layer->setRateLimitContext(m_rateLimitingEnabled);
213 }
214 }
215
216 size_t Canvas2DLayerBridge::freeMemoryIfPossible(size_t bytesToFree)
217 {
218 ASSERT(!m_destructionInProgress);
219 size_t bytesFreed = m_canvas->freeMemoryIfPossible(bytesToFree);
220 if (bytesFreed)
221 Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, -((intptr _t)bytesFreed));
222 m_bytesAllocated -= bytesFreed;
223 return bytesFreed;
224 }
225
226 void Canvas2DLayerBridge::flush()
227 {
228 ASSERT(!m_destructionInProgress);
229 if (m_canvas->hasPendingCommands()) {
230 TRACE_EVENT0("cc", "Canvas2DLayerBridge::flush");
231 m_canvas->flush();
232 }
233 }
234
235 WebGraphicsContext3D* Canvas2DLayerBridge::context()
236 {
237 // Check on m_layer is necessary because context() may be called during
238 // the destruction of m_layer
239 if (m_layer) {
240 isValid(); // To ensure rate limiter is disabled if context is lost.
241 }
242 return m_context->webContext();
243 }
244
245 bool Canvas2DLayerBridge::isValid()
246 {
247 ASSERT(m_layer);
248 if (m_destructionInProgress)
249 return false;
250 if (m_context->webContext()->isContextLost() || !m_surfaceIsValid) {
251 // Attempt to recover.
252 m_layer->clearTexture();
253 m_mailboxes.clear();
254 RefPtr<GraphicsContext3D> sharedContext = SharedGraphicsContext3D::get() ;
255 if (!sharedContext || sharedContext->webContext()->isContextLost()) {
256 m_surfaceIsValid = false;
257 } else {
258 m_context = sharedContext;
259 IntSize size(m_canvas->getTopDevice()->width(), m_canvas->getTopDevi ce()->height());
260 SkAutoTUnref<SkSurface> surface(createSurface(m_context.get(), size, m_msaaSampleCount));
261 if (surface.get()) {
262 m_canvas->setSurface(surface.get());
263 m_surfaceIsValid = true;
264 // FIXME: draw sad canvas picture into new buffer crbug.com/2438 42
265 } else {
266 // Surface allocation failed. Set m_surfaceIsValid to false to
267 // trigger subsequent retry.
268 m_surfaceIsValid = false;
269 }
270 }
271 }
272 if (!m_surfaceIsValid)
273 setRateLimitingEnabled(false);
274 return m_surfaceIsValid;
275 }
276
277 bool Canvas2DLayerBridge::prepareMailbox(blink::WebExternalTextureMailbox* outMa ilbox, blink::WebExternalBitmap* bitmap)
278 {
279 if (bitmap) {
280 // Using accelerated 2d canvas with software renderer, which
281 // should only happen in tests that use fake graphics contexts.
282 // In this case, we do not care about producing any results for
283 // compositing.
284 m_canvas->silentFlush();
285 return false;
286 }
287 if (!isValid())
288 return false;
289 // Release to skia textures that were previouosly released by the
290 // compositor. We do this before acquiring the next snapshot in
291 // order to cap maximum gpu memory consumption.
292 m_context->makeContextCurrent();
293 flush();
294 Vector<MailboxInfo>::iterator mailboxInfo;
295 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mai lboxInfo++) {
296 if (mailboxInfo->m_status == MailboxReleased) {
297 if (mailboxInfo->m_mailbox.syncPoint) {
298 context()->waitSyncPoint(mailboxInfo->m_mailbox.syncPoint);
299 mailboxInfo->m_mailbox.syncPoint = 0;
300 }
301 // Invalidate texture state in case the compositor altered it since the copy-on-write.
302 mailboxInfo->m_image->getTexture()->invalidateCachedState();
303 mailboxInfo->m_image.reset(0);
304 mailboxInfo->m_status = MailboxAvailable;
305 }
306 }
307 SkAutoTUnref<SkImage> image(m_canvas->newImageSnapshot());
308 // Early exit if canvas was not drawn to since last prepareMailbox
309 if (image->uniqueID() == m_lastImageId)
310 return false;
311 m_lastImageId = image->uniqueID();
312
313 mailboxInfo = createMailboxInfo();
314 mailboxInfo->m_status = MailboxInUse;
315 mailboxInfo->m_image.swap(&image);
316 // Because of texture sharing with the compositor, we must invalidate
317 // the state cached in skia so that the deferred copy on write
318 // in SkSurface_Gpu does not make any false assumptions.
319 mailboxInfo->m_image->getTexture()->invalidateCachedState();
320
321 ASSERT(mailboxInfo->m_mailbox.syncPoint == 0);
322 ASSERT(mailboxInfo->m_image.get());
323 ASSERT(mailboxInfo->m_image->getTexture());
324
325 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, mailboxInfo->m_image-> getTexture()->getTextureHandle());
326 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T EXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
327 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T EXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
328 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T EXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
329 m_context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::T EXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
330 context()->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, mailboxInfo ->m_mailbox.name);
331 context()->flush();
332 mailboxInfo->m_mailbox.syncPoint = context()->insertSyncPoint();
333 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
334 // Because we are changing the texture binding without going through skia,
335 // we must dirty the context.
336 m_context->grContext()->resetContext(kTextureBinding_GrGLBackendState);
337
338 // set m_parentLayerBridge to make sure 'this' stays alive as long as it has
339 // live mailboxes
340 ASSERT(!mailboxInfo->m_parentLayerBridge);
341 mailboxInfo->m_parentLayerBridge = this;
342 *outMailbox = mailboxInfo->m_mailbox;
343 return true;
344 }
345
346 Canvas2DLayerBridge::MailboxInfo* Canvas2DLayerBridge::createMailboxInfo() {
347 ASSERT(!m_destructionInProgress);
348 MailboxInfo* mailboxInfo;
349 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mai lboxInfo++) {
350 if (mailboxInfo->m_status == MailboxAvailable) {
351 return mailboxInfo;
352 }
353 }
354
355 // No available mailbox: create one.
356 m_mailboxes.grow(m_mailboxes.size() + 1);
357 mailboxInfo = &m_mailboxes.last();
358 context()->genMailboxCHROMIUM(mailboxInfo->m_mailbox.name);
359 // Worst case, canvas is triple buffered. More than 3 active mailboxes
360 // means there is a problem.
361 // For the single-threaded case, this value needs to be at least
362 // kMaxSwapBuffersPending+1 (in render_widget.h).
363 // Because of crbug.com/247874, it needs to be kMaxSwapBuffersPending+2.
364 // TODO(piman): fix this.
365 ASSERT(m_mailboxes.size() <= 4);
366 ASSERT(mailboxInfo < m_mailboxes.end());
367 return mailboxInfo;
368 }
369
370 void Canvas2DLayerBridge::mailboxReleased(const blink::WebExternalTextureMailbox & mailbox)
371 {
372 Vector<MailboxInfo>::iterator mailboxInfo;
373 for (mailboxInfo = m_mailboxes.begin(); mailboxInfo < m_mailboxes.end(); mai lboxInfo++) {
374 if (!memcmp(mailboxInfo->m_mailbox.name, mailbox.name, sizeof(mailbox.na me))) {
375 mailboxInfo->m_mailbox.syncPoint = mailbox.syncPoint;
376 ASSERT(mailboxInfo->m_status == MailboxInUse);
377 mailboxInfo->m_status = MailboxReleased;
378 // Trigger Canvas2DLayerBridge self-destruction if this is the
379 // last live mailbox and the layer bridge is not externally
380 // referenced.
381 ASSERT(mailboxInfo->m_parentLayerBridge.get() == this);
382 mailboxInfo->m_parentLayerBridge.clear();
383 return;
384 }
385 }
386 }
387
388 blink::WebLayer* Canvas2DLayerBridge::layer()
389 {
390 ASSERT(m_layer);
391 return m_layer->layer();
392 }
393
394 void Canvas2DLayerBridge::contextAcquired()
395 {
396 ASSERT(!m_destructionInProgress);
397 Canvas2DLayerManager::get().layerDidDraw(this);
398 m_didRecordDrawCommand = true;
399 }
400
401 unsigned Canvas2DLayerBridge::backBufferTexture()
402 {
403 ASSERT(!m_destructionInProgress);
404 if (!isValid())
405 return 0;
406 contextAcquired();
407 m_canvas->flush();
408 m_context->flush();
409 GrRenderTarget* renderTarget = reinterpret_cast<GrRenderTarget*>(m_canvas->g etDevice()->accessRenderTarget());
410 if (renderTarget) {
411 return renderTarget->asTexture()->getTextureHandle();
412 }
413 return 0;
414 }
415
416 Canvas2DLayerBridge::MailboxInfo::MailboxInfo(const MailboxInfo& other) {
417 // This copy constructor should only be used for Vector reallocation
418 // Assuming 'other' is to be destroyed, we swap m_image ownership
419 // rather than do a refcount dance.
420 memcpy(&m_mailbox, &other.m_mailbox, sizeof(m_mailbox));
421 m_image.swap(const_cast<SkAutoTUnref<SkImage>*>(&other.m_image));
422 m_status = other.m_status;
423 }
424
425 }
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/Canvas2DLayerBridge.h ('k') | Source/core/platform/graphics/Canvas2DLayerBridgeTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698