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 "platform/graphics/gpu/DrawingBuffer.h"
34
35 #include "platform/RuntimeEnabledFeatures.h"
36 #include <algorithm>
37 #include "platform/TraceEvent.h"
38 #include "platform/graphics/GraphicsLayer.h"
39 #include "platform/graphics/gpu/Extensions3DUtil.h"
40 #include "public/platform/Platform.h"
41 #include "public/platform/WebCompositorSupport.h"
42 #include "public/platform/WebExternalBitmap.h"
43 #include "public/platform/WebExternalTextureLayer.h"
44 #include "public/platform/WebGraphicsContext3D.h"
45 #include "public/platform/WebGraphicsContext3DProvider.h"
46 #ifndef NDEBUG
47 #include "wtf/RefCountedLeakCounter.h"
48 #endif
49
50 using namespace std;
51
52 namespace WebCore {
53
54 namespace {
55 // Global resource ceiling (expressed in terms of pixels) for DrawingBuffer creation and resize.
56 // When this limit is set, DrawingBuffer::create() and DrawingBuffer::reset() calls that would
57 // exceed the global cap will instead clear the buffer.
58 const int s_maximumResourceUsePixels = 16 * 1024 * 1024;
59 int s_currentResourceUsePixels = 0;
60 const float s_resourceAdjustedRatio = 0.5;
61
62 const bool s_allowContextEvictionOnCreate = true;
63 const int s_maxScaleAttempts = 3;
64
65 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, drawingBufferCounter, ("DrawingBuffer"));
66
67 class ScopedTextureUnit0BindingRestorer {
68 public:
ScopedTextureUnit0BindingRestorer(blink::WebGraphicsContext3D * context,GLenum activeTextureUnit,Platform3DObject textureUnitZeroId)69 ScopedTextureUnit0BindingRestorer(blink::WebGraphicsContext3D* context, GLenum activeTextureUnit, Platform3DObject textureUnitZeroId)
70 : m_context(context)
71 , m_oldActiveTextureUnit(activeTextureUnit)
72 , m_oldTextureUnitZeroId(textureUnitZeroId)
73 {
74 m_context->activeTexture(GL_TEXTURE0);
75 }
~ScopedTextureUnit0BindingRestorer()76 ~ScopedTextureUnit0BindingRestorer()
77 {
78 m_context->bindTexture(GL_TEXTURE_2D, m_oldTextureUnitZeroId);
79 m_context->activeTexture(m_oldActiveTextureUnit);
80 }
81
82 private:
83 blink::WebGraphicsContext3D* m_context;
84 GLenum m_oldActiveTextureUnit;
85 Platform3DObject m_oldTextureUnitZeroId;
86 };
87
88 } // namespace
89
create(PassOwnPtr<blink::WebGraphicsContext3D> context,const IntSize & size,PreserveDrawingBuffer preserve,blink::WebGraphicsContext3D::Attributes requestedAttributes,PassRefPtr<ContextEvictionManager> contextEvictionManager)90 PassRefPtr<DrawingBuffer> DrawingBuffer::create(PassOwnPtr<blink::WebGraphicsContext3D> context, const IntSize& size, PreserveDrawingBuffer preserve, blink::WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr<ContextEvictionManager> contextEvictionManager)
91 {
92 ASSERT(context);
93 OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(context.get());
94 if (!extensionsUtil) {
95 // This might be the first time we notice that the WebGraphicsContext3D is lost.
96 return nullptr;
97 }
98 bool multisampleSupported = extensionsUtil->supportsExtension("GL_CHROMIUM_framebuffer_multisample")
99 && extensionsUtil->supportsExtension("GL_OES_rgb8_rgba8");
100 if (multisampleSupported) {
101 extensionsUtil->ensureExtensionEnabled("GL_CHROMIUM_framebuffer_multisample");
102 extensionsUtil->ensureExtensionEnabled("GL_OES_rgb8_rgba8");
103 }
104 bool packedDepthStencilSupported = extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil");
105 if (packedDepthStencilSupported)
106 extensionsUtil->ensureExtensionEnabled("GL_OES_packed_depth_stencil");
107
108 RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, extensionsUtil.release(), multisampleSupported, packedDepthStencilSupported, preserve, requestedAttributes, contextEvictionManager));
109 if (!drawingBuffer->initialize(size)) {
110 drawingBuffer->beginDestruction();
111 return PassRefPtr<DrawingBuffer>();
112 }
113 return drawingBuffer.release();
114 }
115
DrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context,PassOwnPtr<Extensions3DUtil> extensionsUtil,bool multisampleExtensionSupported,bool packedDepthStencilExtensionSupported,PreserveDrawingBuffer preserve,blink::WebGraphicsContext3D::Attributes requestedAttributes,PassRefPtr<ContextEvictionManager> contextEvictionManager)116 DrawingBuffer::DrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context,
117 PassOwnPtr<Extensions3DUtil> extensionsUtil,
118 bool multisampleExtensionSupported,
119 bool packedDepthStencilExtensionSupported,
120 PreserveDrawingBuffer preserve,
121 blink::WebGraphicsContext3D::Attributes requestedAttributes,
122 PassRefPtr<ContextEvictionManager> contextEvictionManager)
123 : m_preserveDrawingBuffer(preserve)
124 , m_scissorEnabled(false)
125 , m_texture2DBinding(0)
126 , m_framebufferBinding(0)
127 , m_activeTextureUnit(GL_TEXTURE0)
128 , m_context(context)
129 , m_extensionsUtil(extensionsUtil)
130 , m_size(-1, -1)
131 , m_requestedAttributes(requestedAttributes)
132 , m_multisampleExtensionSupported(multisampleExtensionSupported)
133 , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported)
134 , m_fbo(0)
135 , m_depthStencilBuffer(0)
136 , m_depthBuffer(0)
137 , m_stencilBuffer(0)
138 , m_multisampleFBO(0)
139 , m_multisampleColorBuffer(0)
140 , m_contentsChanged(true)
141 , m_contentsChangeCommitted(false)
142 , m_layerComposited(false)
143 , m_multisampleMode(None)
144 , m_internalColorFormat(0)
145 , m_colorFormat(0)
146 , m_internalRenderbufferFormat(0)
147 , m_maxTextureSize(0)
148 , m_sampleCount(0)
149 , m_packAlignment(4)
150 , m_destructionInProgress(false)
151 , m_contextEvictionManager(contextEvictionManager)
152 {
153 // Used by browser tests to detect the use of a DrawingBuffer.
154 TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation");
155 #ifndef NDEBUG
156 drawingBufferCounter.increment();
157 #endif
158 }
159
~DrawingBuffer()160 DrawingBuffer::~DrawingBuffer()
161 {
162 ASSERT(m_destructionInProgress);
163 ASSERT(m_textureMailboxes.isEmpty());
164 m_layer.clear();
165 m_context.clear();
166 #ifndef NDEBUG
167 drawingBufferCounter.decrement();
168 #endif
169 }
170
markContentsChanged()171 void DrawingBuffer::markContentsChanged()
172 {
173 m_contentsChanged = true;
174 m_contentsChangeCommitted = false;
175 m_layerComposited = false;
176 }
177
layerComposited() const178 bool DrawingBuffer::layerComposited() const
179 {
180 return m_layerComposited;
181 }
182
markLayerComposited()183 void DrawingBuffer::markLayerComposited()
184 {
185 m_layerComposited = true;
186 }
187
context()188 blink::WebGraphicsContext3D* DrawingBuffer::context()
189 {
190 return m_context.get();
191 }
192
prepareMailbox(blink::WebExternalTextureMailbox * outMailbox,blink::WebExternalBitmap * bitmap)193 bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap)
194 {
195 if (!m_contentsChanged)
196 return false;
197
198 if (m_destructionInProgress) {
199 // It can be hit in the following sequence.
200 // 1. WebGL draws something.
201 // 2. The compositor begins the frame.
202 // 3. Javascript makes a context lost using WEBGL_lose_context extension.
203 // 4. Here.
204 return false;
205 }
206
207 m_context->makeContextCurrent();
208
209 // Resolve the multisampled buffer into m_colorBuffer texture.
210 if (m_multisampleMode != None)
211 commit();
212
213 if (bitmap) {
214 bitmap->setSize(size());
215
216 unsigned char* pixels = bitmap->pixels();
217 bool needPremultiply = m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha;
218 WebGLImageConversion::AlphaOp op = needPremultiply ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing;
219 if (pixels)
220 readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, op);
221 }
222
223 // We must restore the texture binding since creating new textures,
224 // consuming and producing mailboxes changes it.
225 ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureUnit, m_texture2DBinding);
226
227 // First try to recycle an old buffer.
228 RefPtr<MailboxInfo> frontColorBufferMailbox = recycledMailbox();
229
230 // No buffer available to recycle, create a new one.
231 if (!frontColorBufferMailbox) {
232 TextureInfo newTexture;
233 newTexture.textureId = createColorTexture();
234 allocateTextureMemory(&newTexture, m_size);
235 // Bad things happened, abandon ship.
236 if (!newTexture.textureId)
237 return false;
238
239 frontColorBufferMailbox = createNewMailbox(newTexture);
240 }
241
242 if (m_preserveDrawingBuffer == Discard) {
243 swap(frontColorBufferMailbox->textureInfo, m_colorBuffer);
244 // It appears safe to overwrite the context's framebuffer binding in the Discard case since there will always be a
245 // WebGLRenderingContext::clearIfComposited() call made before the next draw call which restores the framebuffer binding.
246 // If this stops being true at some point, we should track the current framebuffer binding in the DrawingBuffer and restore
247 // it after attaching the new back buffer here.
248 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
249 if (m_multisampleMode == ImplicitResolve)
250 m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount);
251 else
252 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0);
253 } else {
254 m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE);
255 }
256
257 if (m_multisampleMode != None && !m_framebufferBinding)
258 bind();
259 else
260 restoreFramebufferBinding();
261
262 m_contentsChanged = false;
263
264 m_context->bindTexture(GL_TEXTURE_2D, frontColorBufferMailbox->textureInfo.textureId);
265 m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, frontColorBufferMailbox->mailbox.name);
266 m_context->flush();
267 frontColorBufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint();
268 frontColorBufferMailbox->mailbox.allowOverlay = frontColorBufferMailbox->textureInfo.imageId != 0;
269 markLayerComposited();
270
271 // set m_parentDrawingBuffer to make sure 'this' stays alive as long as it has live mailboxes
272 ASSERT(!frontColorBufferMailbox->m_parentDrawingBuffer);
273 frontColorBufferMailbox->m_parentDrawingBuffer = this;
274 *outMailbox = frontColorBufferMailbox->mailbox;
275 m_frontColorBuffer = frontColorBufferMailbox->textureInfo;
276 return true;
277 }
278
mailboxReleased(const blink::WebExternalTextureMailbox & mailbox)279 void DrawingBuffer::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox)
280 {
281 if (m_destructionInProgress) {
282 mailboxReleasedWhileDestructionInProgress(mailbox);
283 return;
284 }
285
286 for (size_t i = 0; i < m_textureMailboxes.size(); i++) {
287 RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i];
288 if (nameEquals(mailboxInfo->mailbox, mailbox)) {
289 mailboxInfo->mailbox.syncPoint = mailbox.syncPoint;
290 ASSERT(mailboxInfo->m_parentDrawingBuffer.get() == this);
291 mailboxInfo->m_parentDrawingBuffer.clear();
292 m_recycledMailboxQueue.prepend(mailboxInfo->mailbox);
293 return;
294 }
295 }
296 ASSERT_NOT_REACHED();
297 }
298
mailboxReleasedWhileDestructionInProgress(const blink::WebExternalTextureMailbox & mailbox)299 void DrawingBuffer::mailboxReleasedWhileDestructionInProgress(const blink::WebExternalTextureMailbox& mailbox)
300 {
301 ASSERT(m_textureMailboxes.size());
302 m_context->makeContextCurrent();
303 // Ensure not to call the destructor until deleteMailbox() is completed.
304 RefPtr<DrawingBuffer> self = this;
305 deleteMailbox(mailbox);
306 }
307
recycledMailbox()308 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::recycledMailbox()
309 {
310 if (m_recycledMailboxQueue.isEmpty())
311 return PassRefPtr<MailboxInfo>();
312
313 blink::WebExternalTextureMailbox mailbox = m_recycledMailboxQueue.takeLast();
314 RefPtr<MailboxInfo> mailboxInfo;
315 for (size_t i = 0; i < m_textureMailboxes.size(); i++) {
316 if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) {
317 mailboxInfo = m_textureMailboxes[i];
318 break;
319 }
320 }
321 ASSERT(mailboxInfo);
322
323 if (mailboxInfo->mailbox.syncPoint) {
324 m_context->waitSyncPoint(mailboxInfo->mailbox.syncPoint);
325 mailboxInfo->mailbox.syncPoint = 0;
326 }
327
328 if (mailboxInfo->size != m_size) {
329 m_context->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureInfo.textureId);
330 allocateTextureMemory(&mailboxInfo->textureInfo, m_size);
331 mailboxInfo->size = m_size;
332 }
333
334 return mailboxInfo.release();
335 }
336
createNewMailbox(const TextureInfo & info)337 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(const TextureInfo& info)
338 {
339 RefPtr<MailboxInfo> returnMailbox = adoptRef(new MailboxInfo());
340 m_context->genMailboxCHROMIUM(returnMailbox->mailbox.name);
341 returnMailbox->textureInfo = info;
342 returnMailbox->size = m_size;
343 m_textureMailboxes.append(returnMailbox);
344 return returnMailbox.release();
345 }
346
deleteMailbox(const blink::WebExternalTextureMailbox & mailbox)347 void DrawingBuffer::deleteMailbox(const blink::WebExternalTextureMailbox& mailbox)
348 {
349 for (size_t i = 0; i < m_textureMailboxes.size(); i++) {
350 if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) {
351 if (mailbox.syncPoint)
352 m_context->waitSyncPoint(mailbox.syncPoint);
353
354 deleteChromiumImageForTexture(&m_textureMailboxes[i]->textureInfo);
355
356 m_context->deleteTexture(m_textureMailboxes[i]->textureInfo.textureId);
357 m_textureMailboxes.remove(i);
358 return;
359 }
360 }
361 ASSERT_NOT_REACHED();
362 }
363
initialize(const IntSize & size)364 bool DrawingBuffer::initialize(const IntSize& size)
365 {
366 if (!m_context->makeContextCurrent()) {
367 // Most likely the GPU process exited and the attempt to reconnect to it failed.
368 // Need to try to restore the context again later.
369 return false;
370 }
371
372 if (m_context->isContextLost()) {
373 // Need to try to restore the context again later.
374 return false;
375 }
376
377 if (m_requestedAttributes.alpha) {
378 m_internalColorFormat = GL_RGBA;
379 m_colorFormat = GL_RGBA;
380 m_internalRenderbufferFormat = GL_RGBA8_OES;
381 } else {
382 m_internalColorFormat = GL_RGB;
383 m_colorFormat = GL_RGB;
384 m_internalRenderbufferFormat = GL_RGB8_OES;
385 }
386
387 m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
388
389 int maxSampleCount = 0;
390 m_multisampleMode = None;
391 if (m_requestedAttributes.antialias && m_multisampleExtensionSupported) {
392 m_context->getIntegerv(GL_MAX_SAMPLES_ANGLE, &maxSampleCount);
393 m_multisampleMode = ExplicitResolve;
394 if (m_extensionsUtil->supportsExtension("GL_EXT_multisampled_render_to_texture"))
395 m_multisampleMode = ImplicitResolve;
396 }
397 m_sampleCount = std::min(4, maxSampleCount);
398
399 m_fbo = m_context->createFramebuffer();
400
401 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
402 m_colorBuffer.textureId = createColorTexture();
403 if (m_multisampleMode == ImplicitResolve)
404 m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount);
405 else
406 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0);
407 createSecondaryBuffers();
408 // We first try to initialize everything with the requested attributes.
409 if (!reset(size))
410 return false;
411 // If that succeeds, we then see what we actually got and update our actual attributes to reflect that.
412 m_actualAttributes = m_requestedAttributes;
413 if (m_requestedAttributes.alpha) {
414 blink::WGC3Dint alphaBits = 0;
415 m_context->getIntegerv(GL_ALPHA_BITS, &alphaBits);
416 m_actualAttributes.alpha = alphaBits > 0;
417 }
418 if (m_requestedAttributes.depth) {
419 blink::WGC3Dint depthBits = 0;
420 m_context->getIntegerv(GL_DEPTH_BITS, &depthBits);
421 m_actualAttributes.depth = depthBits > 0;
422 }
423 if (m_requestedAttributes.stencil) {
424 blink::WGC3Dint stencilBits = 0;
425 m_context->getIntegerv(GL_STENCIL_BITS, &stencilBits);
426 m_actualAttributes.stencil = stencilBits > 0;
427 }
428 m_actualAttributes.antialias = multisample();
429 return true;
430 }
431
copyToPlatformTexture(blink::WebGraphicsContext3D * context,Platform3DObject texture,GLenum internalFormat,GLenum destType,GLint level,bool premultiplyAlpha,bool flipY,bool fromFrontBuffer)432 bool DrawingBuffer::copyToPlatformTexture(blink::WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, bool fromFrontBuffer)
433 {
434 if (!m_context->makeContextCurrent())
435 return false;
436
437 GLint textureId = m_colorBuffer.textureId;
438 if (fromFrontBuffer)
439 textureId = m_frontColorBuffer.textureId;
440
441 if (m_contentsChanged) {
442 if (m_multisampleMode != None) {
443 commit();
444 if (!m_framebufferBinding)
445 bind();
446 else
447 restoreFramebufferBinding();
448 }
449 m_context->flush();
450 }
451
452 if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level))
453 return false;
454
455 // Contexts may be in a different share group. We must transfer the texture through a mailbox first
456 RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo());
457 m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name);
458 m_context->produceTextureDirectCHROMIUM(textureId, GL_TEXTURE_2D, bufferMailbox->mailbox.name);
459 m_context->flush();
460
461 bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint();
462
463 if (!context->makeContextCurrent())
464 return false;
465
466 context->waitSyncPoint(bufferMailbox->mailbox.syncPoint);
467 Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name);
468
469 bool unpackPremultiplyAlphaNeeded = false;
470 bool unpackUnpremultiplyAlphaNeeded = false;
471 if (m_actualAttributes.alpha && m_actualAttributes.premultipliedAlpha && !premultiplyAlpha)
472 unpackUnpremultiplyAlphaNeeded = true;
473 else if (m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha && premultiplyAlpha)
474 unpackPremultiplyAlphaNeeded = true;
475
476 context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded);
477 context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded);
478 context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, flipY);
479 context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType);
480 context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false);
481 context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false);
482 context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false);
483
484 context->deleteTexture(sourceTexture);
485
486 context->flush();
487 m_context->waitSyncPoint(context->insertSyncPoint());
488
489 return true;
490 }
491
framebuffer() const492 Platform3DObject DrawingBuffer::framebuffer() const
493 {
494 return m_fbo;
495 }
496
platformLayer()497 blink::WebLayer* DrawingBuffer::platformLayer()
498 {
499 if (!m_layer) {
500 m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this));
501
502 m_layer->setOpaque(!m_actualAttributes.alpha);
503 m_layer->setBlendBackgroundColor(m_actualAttributes.alpha);
504 m_layer->setPremultipliedAlpha(m_actualAttributes.premultipliedAlpha);
505 GraphicsLayer::registerContentsLayer(m_layer->layer());
506 }
507
508 return m_layer->layer();
509 }
510
paintCompositedResultsToCanvas(ImageBuffer * imageBuffer)511 void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer)
512 {
513 if (!m_context->makeContextCurrent() || m_context->getGraphicsResetStatusARB() != GL_NO_ERROR)
514 return;
515
516 if (!imageBuffer)
517 return;
518 Platform3DObject tex = imageBuffer->getBackingTexture();
519 if (tex) {
520 RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo());
521 m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name);
522 m_context->bindTexture(GL_TEXTURE_2D, m_frontColorBuffer.textureId);
523 m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name);
524 m_context->flush();
525
526 bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint();
527 OwnPtr<blink::WebGraphicsContext3DProvider> provider =
528 adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider());
529 if (!provider)
530 return;
531 blink::WebGraphicsContext3D* context = provider->context3d();
532 if (!context || !context->makeContextCurrent())
533 return;
534
535 Platform3DObject sourceTexture = context->createTexture();
536 GLint boundTexture = 0;
537 context->getIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture);
538 context->bindTexture(GL_TEXTURE_2D, sourceTexture);
539 context->waitSyncPoint(bufferMailbox->mailbox.syncPoint);
540 context->consumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name);
541 context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture,
542 tex, 0, GL_RGBA, GL_UNSIGNED_BYTE);
543 context->bindTexture(GL_TEXTURE_2D, boundTexture);
544 context->deleteTexture(sourceTexture);
545 context->flush();
546 m_context->waitSyncPoint(context->insertSyncPoint());
547 return;
548 }
549
550 // Since the m_frontColorBuffer was produced and sent to the compositor, it cannot be bound to an fbo.
551 // We have to make a copy of it here and bind that copy instead.
552 // FIXME: That's not true any more, provided we don't change texture
553 // parameters.
554 unsigned sourceTexture = createColorTexture();
555 texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE);
556 m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer.textureId, sourceTexture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
557
558 // Since we're using the same context as WebGL, we have to restore any state we change (in this case, just the framebuffer binding).
559 // FIXME: The WebGLRenderingContext tracks the current framebuffer binding, it would be slightly more efficient to use this value
560 // rather than querying it off of the context.
561 GLint previousFramebuffer = 0;
562 m_context->getIntegerv(GL_FRAMEBUFFER_BINDING, &previousFramebuffer);
563
564 Platform3DObject framebuffer = m_context->createFramebuffer();
565 m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
566 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 0);
567
568 paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer);
569 m_context->deleteFramebuffer(framebuffer);
570 m_context->deleteTexture(sourceTexture);
571
572 m_context->bindFramebuffer(GL_FRAMEBUFFER, previousFramebuffer);
573 }
574
clearPlatformLayer()575 void DrawingBuffer::clearPlatformLayer()
576 {
577 if (m_layer)
578 m_layer->clearTexture();
579
580 m_context->flush();
581 }
582
beginDestruction()583 void DrawingBuffer::beginDestruction()
584 {
585 ASSERT(!m_destructionInProgress);
586 m_destructionInProgress = true;
587
588 m_context->makeContextCurrent();
589
590 clearPlatformLayer();
591
592 while (!m_recycledMailboxQueue.isEmpty())
593 deleteMailbox(m_recycledMailboxQueue.takeLast());
594
595 if (m_multisampleFBO)
596 m_context->deleteFramebuffer(m_multisampleFBO);
597
598 if (m_fbo)
599 m_context->deleteFramebuffer(m_fbo);
600
601 if (m_multisampleColorBuffer)
602 m_context->deleteRenderbuffer(m_multisampleColorBuffer);
603
604 if (m_depthStencilBuffer)
605 m_context->deleteRenderbuffer(m_depthStencilBuffer);
606
607 if (m_depthBuffer)
608 m_context->deleteRenderbuffer(m_depthBuffer);
609
610 if (m_stencilBuffer)
611 m_context->deleteRenderbuffer(m_stencilBuffer);
612
613 if (m_colorBuffer.textureId) {
614 deleteChromiumImageForTexture(&m_colorBuffer);
615 m_context->deleteTexture(m_colorBuffer.textureId);
616 }
617
618 setSize(IntSize());
619
620 m_colorBuffer = TextureInfo();
621 m_frontColorBuffer = TextureInfo();
622 m_multisampleColorBuffer = 0;
623 m_depthStencilBuffer = 0;
624 m_depthBuffer = 0;
625 m_stencilBuffer = 0;
626 m_multisampleFBO = 0;
627 m_fbo = 0;
628 m_contextEvictionManager.clear();
629
630 if (m_layer)
631 GraphicsLayer::unregisterContentsLayer(m_layer->layer());
632 }
633
createColorTexture()634 unsigned DrawingBuffer::createColorTexture()
635 {
636 unsigned offscreenColorTexture = m_context->createTexture();
637 if (!offscreenColorTexture)
638 return 0;
639
640 m_context->bindTexture(GL_TEXTURE_2D, offscreenColorTexture);
641 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
642 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
643 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
644 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
645
646 return offscreenColorTexture;
647 }
648
createSecondaryBuffers()649 void DrawingBuffer::createSecondaryBuffers()
650 {
651 // create a multisample FBO
652 if (m_multisampleMode == ExplicitResolve) {
653 m_multisampleFBO = m_context->createFramebuffer();
654 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
655 m_multisampleColorBuffer = m_context->createRenderbuffer();
656 }
657 }
658
resizeFramebuffer(const IntSize & size)659 bool DrawingBuffer::resizeFramebuffer(const IntSize& size)
660 {
661 // resize regular FBO
662 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
663
664 m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer.textureId);
665
666 allocateTextureMemory(&m_colorBuffer, size);
667
668 if (m_multisampleMode == ImplicitResolve)
669 m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount);
670 else
671 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0);
672
673 m_context->bindTexture(GL_TEXTURE_2D, 0);
674
675 if (m_multisampleMode != ExplicitResolve)
676 resizeDepthStencil(size);
677 if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
678 return false;
679
680 return true;
681 }
682
resizeMultisampleFramebuffer(const IntSize & size)683 bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size)
684 {
685 if (m_multisampleMode == ExplicitResolve) {
686 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
687
688 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleColorBuffer);
689 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, m_internalRenderbufferFormat, size.width(), size.height());
690
691 if (m_context->getError() == GL_OUT_OF_MEMORY)
692 return false;
693
694 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleColorBuffer);
695 resizeDepthStencil(size);
696 if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
697 return false;
698 }
699
700 return true;
701 }
702
resizeDepthStencil(const IntSize & size)703 void DrawingBuffer::resizeDepthStencil(const IntSize& size)
704 {
705 if (!m_requestedAttributes.depth && !m_requestedAttributes.stencil)
706 return;
707
708 if (m_packedDepthStencilExtensionSupported) {
709 if (!m_depthStencilBuffer)
710 m_depthStencilBuffer = m_context->createRenderbuffer();
711 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
712 if (m_multisampleMode == ImplicitResolve)
713 m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height());
714 else if (m_multisampleMode == ExplicitResolve)
715 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height());
716 else
717 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, size.width(), size.height());
718 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
719 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
720 } else {
721 if (m_requestedAttributes.depth) {
722 if (!m_depthBuffer)
723 m_depthBuffer = m_context->createRenderbuffer();
724 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
725 if (m_multisampleMode == ImplicitResolve)
726 m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height());
727 else if (m_multisampleMode == ExplicitResolve)
728 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height());
729 else
730 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height());
731 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
732 }
733 if (m_requestedAttributes.stencil) {
734 if (!m_stencilBuffer)
735 m_stencilBuffer = m_context->createRenderbuffer();
736 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer);
737 if (m_multisampleMode == ImplicitResolve)
738 m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height());
739 else if (m_multisampleMode == ExplicitResolve)
740 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height());
741 else
742 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, size.width(), size.height());
743 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer);
744 }
745 }
746 m_context->bindRenderbuffer(GL_RENDERBUFFER, 0);
747 }
748
749
750
clearFramebuffers(GLbitfield clearMask)751 void DrawingBuffer::clearFramebuffers(GLbitfield clearMask)
752 {
753 // We will clear the multisample FBO, but we also need to clear the non-multisampled buffer.
754 if (m_multisampleFBO) {
755 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
756 m_context->clear(GL_COLOR_BUFFER_BIT);
757 }
758
759 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
760 m_context->clear(clearMask);
761 }
762
setSize(const IntSize & size)763 void DrawingBuffer::setSize(const IntSize& size)
764 {
765 if (m_size == size)
766 return;
767
768 s_currentResourceUsePixels += pixelDelta(size, m_size);
769 m_size = size;
770 }
771
pixelDelta(const IntSize & newSize,const IntSize & curSize)772 int DrawingBuffer::pixelDelta(const IntSize& newSize, const IntSize& curSize)
773 {
774 return (max(0, newSize.width()) * max(0, newSize.height())) - (max(0, curSize.width()) * max(0, curSize.height()));
775 }
776
adjustSize(const IntSize & desiredSize,const IntSize & curSize,int maxTextureSize)777 IntSize DrawingBuffer::adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize)
778 {
779 IntSize adjustedSize = desiredSize;
780
781 // Clamp if the desired size is greater than the maximum texture size for the device.
782 if (adjustedSize.height() > maxTextureSize)
783 adjustedSize.setHeight(maxTextureSize);
784
785 if (adjustedSize.width() > maxTextureSize)
786 adjustedSize.setWidth(maxTextureSize);
787
788 // Try progressively smaller sizes until we find a size that fits or reach a scale limit.
789 int scaleAttempts = 0;
790 while ((s_currentResourceUsePixels + pixelDelta(adjustedSize, curSize)) > s_maximumResourceUsePixels) {
791 scaleAttempts++;
792 if (scaleAttempts > s_maxScaleAttempts)
793 return IntSize();
794
795 adjustedSize.scale(s_resourceAdjustedRatio);
796
797 if (adjustedSize.isEmpty())
798 return IntSize();
799 }
800
801 return adjustedSize;
802 }
803
adjustSizeWithContextEviction(const IntSize & size,bool & evictContext)804 IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext)
805 {
806 IntSize adjustedSize = adjustSize(size, m_size, m_maxTextureSize);
807 if (!adjustedSize.isEmpty()) {
808 evictContext = false;
809 return adjustedSize; // Buffer fits without evicting a context.
810 }
811
812 // Speculatively adjust the pixel budget to see if the buffer would fit should the oldest context be evicted.
813 IntSize oldestSize = m_contextEvictionManager->oldestContextSize();
814 int pixelDelta = oldestSize.width() * oldestSize.height();
815
816 s_currentResourceUsePixels -= pixelDelta;
817 adjustedSize = adjustSize(size, m_size, m_maxTextureSize);
818 s_currentResourceUsePixels += pixelDelta;
819
820 evictContext = !adjustedSize.isEmpty();
821 return adjustedSize;
822 }
823
reset(const IntSize & newSize)824 bool DrawingBuffer::reset(const IntSize& newSize)
825 {
826 ASSERT(!newSize.isEmpty());
827 IntSize adjustedSize;
828 bool evictContext = false;
829 bool isNewContext = m_size.isEmpty();
830 if (s_allowContextEvictionOnCreate && isNewContext)
831 adjustedSize = adjustSizeWithContextEviction(newSize, evictContext);
832 else
833 adjustedSize = adjustSize(newSize, m_size, m_maxTextureSize);
834
835 if (adjustedSize.isEmpty())
836 return false;
837
838 if (evictContext)
839 m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL contexts have exceeded the maximum allowed backbuffer area. Oldest context will be lost.");
840
841 if (adjustedSize != m_size) {
842 do {
843 // resize multisample FBO
844 if (!resizeMultisampleFramebuffer(adjustedSize) || !resizeFramebuffer(adjustedSize)) {
845 adjustedSize.scale(s_resourceAdjustedRatio);
846 continue;
847 }
848 break;
849 } while (!adjustedSize.isEmpty());
850
851 setSize(adjustedSize);
852
853 if (adjustedSize.isEmpty())
854 return false;
855 }
856
857 m_context->disable(GL_SCISSOR_TEST);
858 m_context->clearColor(0, 0, 0, 0);
859 m_context->colorMask(true, true, true, true);
860
861 GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
862 if (m_actualAttributes.depth) {
863 m_context->clearDepth(1.0f);
864 clearMask |= GL_DEPTH_BUFFER_BIT;
865 m_context->depthMask(true);
866 }
867 if (m_actualAttributes.stencil) {
868 m_context->clearStencil(0);
869 clearMask |= GL_STENCIL_BUFFER_BIT;
870 m_context->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
871 }
872
873 clearFramebuffers(clearMask);
874 return true;
875 }
876
commit(long x,long y,long width,long height)877 void DrawingBuffer::commit(long x, long y, long width, long height)
878 {
879 if (width < 0)
880 width = m_size.width();
881 if (height < 0)
882 height = m_size.height();
883
884 m_context->makeContextCurrent();
885
886 if (m_multisampleFBO && !m_contentsChangeCommitted) {
887 m_context->bindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_multisampleFBO);
888 m_context->bindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, m_fbo);
889
890 if (m_scissorEnabled)
891 m_context->disable(GL_SCISSOR_TEST);
892
893 // Use NEAREST, because there is no scale performed during the blit.
894 m_context->blitFramebufferCHROMIUM(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
895
896 if (m_scissorEnabled)
897 m_context->enable(GL_SCISSOR_TEST);
898 }
899
900 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
901 m_contentsChangeCommitted = true;
902 }
903
restoreFramebufferBinding()904 void DrawingBuffer::restoreFramebufferBinding()
905 {
906 if (!m_framebufferBinding)
907 return;
908
909 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding);
910 }
911
multisample() const912 bool DrawingBuffer::multisample() const
913 {
914 return m_multisampleMode != None;
915 }
916
bind()917 void DrawingBuffer::bind()
918 {
919 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
920 }
921
setPackAlignment(GLint param)922 void DrawingBuffer::setPackAlignment(GLint param)
923 {
924 m_packAlignment = param;
925 }
926
paintRenderingResultsToCanvas(ImageBuffer * imageBuffer)927 void DrawingBuffer::paintRenderingResultsToCanvas(ImageBuffer* imageBuffer)
928 {
929 paintFramebufferToCanvas(framebuffer(), size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer);
930 }
931
paintRenderingResultsToImageData(int & width,int & height)932 PassRefPtr<Uint8ClampedArray> DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height)
933 {
934 if (m_actualAttributes.premultipliedAlpha)
935 return nullptr;
936
937 width = size().width();
938 height = size().height();
939
940 Checked<int, RecordOverflow> dataSize = 4;
941 dataSize *= width;
942 dataSize *= height;
943 if (dataSize.hasOverflowed())
944 return nullptr;
945
946 RefPtr<Uint8ClampedArray> pixels = Uint8ClampedArray::createUninitialized(width * height * 4);
947
948 m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer());
949 readBackFramebuffer(pixels->data(), width, height, ReadbackRGBA, WebGLImageConversion::AlphaDoNothing);
950 flipVertically(pixels->data(), width, height);
951
952 return pixels.release();
953 }
954
paintFramebufferToCanvas(int framebuffer,int width,int height,bool premultiplyAlpha,ImageBuffer * imageBuffer)955 void DrawingBuffer::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer)
956 {
957 unsigned char* pixels = 0;
958
959 const SkBitmap& canvasBitmap = imageBuffer->bitmap();
960 const SkBitmap* readbackBitmap = 0;
961 ASSERT(canvasBitmap.colorType() == kPMColor_SkColorType);
962 if (canvasBitmap.width() == width && canvasBitmap.height() == height) {
963 // This is the fastest and most common case. We read back
964 // directly into the canvas's backing store.
965 readbackBitmap = &canvasBitmap;
966 m_resizingBitmap.reset();
967 } else {
968 // We need to allocate a temporary bitmap for reading back the
969 // pixel data. We will then use Skia to rescale this bitmap to
970 // the size of the canvas's backing store.
971 if (m_resizingBitmap.width() != width || m_resizingBitmap.height() != height) {
972 if (!m_resizingBitmap.allocN32Pixels(width, height))
973 return;
974 }
975 readbackBitmap = &m_resizingBitmap;
976 }
977
978 // Read back the frame buffer.
979 SkAutoLockPixels bitmapLock(*readbackBitmap);
980 pixels = static_cast<unsigned char*>(readbackBitmap->getPixels());
981
982 m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
983 readBackFramebuffer(pixels, width, height, ReadbackSkia, premultiplyAlpha ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing);
984 flipVertically(pixels, width, height);
985
986 readbackBitmap->notifyPixelsChanged();
987 if (m_resizingBitmap.readyToDraw()) {
988 // We need to draw the resizing bitmap into the canvas's backing store.
989 SkCanvas canvas(canvasBitmap);
990 SkRect dst;
991 dst.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(canvasBitmap.width()), SkIntToScalar(canvasBitmap.height()));
992 canvas.drawBitmapRect(m_resizingBitmap, 0, dst);
993 }
994 }
995
readBackFramebuffer(unsigned char * pixels,int width,int height,ReadbackOrder readbackOrder,WebGLImageConversion::AlphaOp op)996 void DrawingBuffer::readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder readbackOrder, WebGLImageConversion::AlphaOp op)
997 {
998 if (m_packAlignment > 4)
999 m_context->pixelStorei(GL_PACK_ALIGNMENT, 1);
1000 m_context->readPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
1001 if (m_packAlignment > 4)
1002 m_context->pixelStorei(GL_PACK_ALIGNMENT, m_packAlignment);
1003
1004 size_t bufferSize = 4 * width * height;
1005
1006 if (readbackOrder == ReadbackSkia) {
1007 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
1008 // Swizzle red and blue channels to match SkBitmap's byte ordering.
1009 // TODO(kbr): expose GL_BGRA as extension.
1010 for (size_t i = 0; i < bufferSize; i += 4) {
1011 std::swap(pixels[i], pixels[i + 2]);
1012 }
1013 #endif
1014 }
1015
1016 if (op == WebGLImageConversion::AlphaDoPremultiply) {
1017 for (size_t i = 0; i < bufferSize; i += 4) {
1018 pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255);
1019 pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255);
1020 pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255);
1021 }
1022 } else if (op != WebGLImageConversion::AlphaDoNothing) {
1023 ASSERT_NOT_REACHED();
1024 }
1025 }
1026
flipVertically(uint8_t * framebuffer,int width,int height)1027 void DrawingBuffer::flipVertically(uint8_t* framebuffer, int width, int height)
1028 {
1029 m_scanline.resize(width * 4);
1030 uint8* scanline = &m_scanline[0];
1031 unsigned rowBytes = width * 4;
1032 unsigned count = height / 2;
1033 for (unsigned i = 0; i < count; i++) {
1034 uint8* rowA = framebuffer + i * rowBytes;
1035 uint8* rowB = framebuffer + (height - i - 1) * rowBytes;
1036 memcpy(scanline, rowB, rowBytes);
1037 memcpy(rowB, rowA, rowBytes);
1038 memcpy(rowA, scanline, rowBytes);
1039 }
1040 }
1041
texImage2DResourceSafe(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,GLint unpackAlignment)1042 void DrawingBuffer::texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint unpackAlignment)
1043 {
1044 ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8);
1045 m_context->texImage2D(target, level, internalformat, width, height, border, format, type, 0);
1046 }
1047
allocateTextureMemory(TextureInfo * info,const IntSize & size)1048 void DrawingBuffer::allocateTextureMemory(TextureInfo* info, const IntSize& size)
1049 {
1050 if (RuntimeEnabledFeatures::webGLImageChromiumEnabled()) {
1051 deleteChromiumImageForTexture(info);
1052
1053 info->imageId = m_context->createImageCHROMIUM(size.width(), size.height(), GL_RGBA8_OES, GC3D_IMAGE_SCANOUT_CHROMIUM);
1054 if (info->imageId) {
1055 m_context->bindTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId);
1056 return;
1057 }
1058 }
1059
1060 texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE);
1061 }
1062
deleteChromiumImageForTexture(TextureInfo * info)1063 void DrawingBuffer::deleteChromiumImageForTexture(TextureInfo* info)
1064 {
1065 if (info->imageId) {
1066 m_context->releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId);
1067 m_context->destroyImageCHROMIUM(info->imageId);
1068 info->imageId = 0;
1069 }
1070 }
1071
1072 } // namespace WebCore
1073