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