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