• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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