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