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

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

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

Powered by Google App Engine
This is Rietveld 408576698