[Chromium] Compositor doesn't support translucent root layers.
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / LayerRendererChromium.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
32 #include "config.h"
33
34 #if USE(ACCELERATED_COMPOSITING)
35 #include "LayerRendererChromium.h"
36
37 #include "Extensions3D.h"
38 #include "Extensions3DChromium.h"
39 #include "FloatQuad.h"
40 #include "GeometryBinding.h"
41 #include "GrTexture.h"
42 #include "GraphicsContext3D.h"
43 #include "ManagedTexture.h"
44 #include "NativeImageSkia.h"
45 #include "NotImplemented.h"
46 #include "PlatformColor.h"
47 #include "PlatformContextSkia.h"
48 #include "SharedGraphicsContext3D.h"
49 #include "SkBitmap.h"
50 #include "TextureCopier.h"
51 #include "TextureManager.h"
52 #include "ThrottledTextureUploader.h"
53 #include "TraceEvent.h"
54 #include "TrackingTextureAllocator.h"
55 #include "cc/CCCheckerboardDrawQuad.h"
56 #include "cc/CCDamageTracker.h"
57 #include "cc/CCDebugBorderDrawQuad.h"
58 #include "cc/CCIOSurfaceDrawQuad.h"
59 #include "cc/CCLayerImpl.h"
60 #include "cc/CCLayerQuad.h"
61 #include "cc/CCLayerTreeHostCommon.h"
62 #include "cc/CCMathUtil.h"
63 #include "cc/CCProxy.h"
64 #include "cc/CCRenderPass.h"
65 #include "cc/CCRenderPassDrawQuad.h"
66 #include "cc/CCRenderSurfaceFilters.h"
67 #include "cc/CCSingleThreadProxy.h"
68 #include "cc/CCSolidColorDrawQuad.h"
69 #include "cc/CCTextureDrawQuad.h"
70 #include "cc/CCTileDrawQuad.h"
71 #include "cc/CCVideoDrawQuad.h"
72 #include <public/WebVideoFrame.h>
73 #include <wtf/CurrentTime.h>
74 #include <wtf/MainThread.h>
75
76 using namespace std;
77 using WebKit::WebTransformationMatrix;
78
79 namespace WebCore {
80
81 namespace {
82
83 static WebTransformationMatrix orthoMatrix(float left, float right, float bottom, float top)
84 {
85     float deltaX = right - left;
86     float deltaY = top - bottom;
87     WebTransformationMatrix ortho;
88     if (!deltaX || !deltaY)
89         return ortho;
90     ortho.setM11(2.0f / deltaX);
91     ortho.setM41(-(right + left) / deltaX);
92     ortho.setM22(2.0f / deltaY);
93     ortho.setM42(-(top + bottom) / deltaY);
94
95     // Z component of vertices is always set to zero as we don't use the depth buffer
96     // while drawing.
97     ortho.setM33(0);
98
99     return ortho;
100 }
101
102 static WebTransformationMatrix screenMatrix(int x, int y, int width, int height)
103 {
104     WebTransformationMatrix screen;
105
106     // Map to viewport.
107     screen.translate3d(x, y, 0);
108     screen.scale3d(width, height, 0);
109
110     // Map x, y and z to unit square.
111     screen.translate3d(0.5, 0.5, 0.5);
112     screen.scale3d(0.5, 0.5, 0.5);
113
114     return screen;
115 }
116
117 bool contextSupportsAcceleratedPainting(GraphicsContext3D* context)
118 {
119     WebCore::Extensions3D* extensions = context->getExtensions();
120     if (extensions->supports("GL_EXT_texture_format_BGRA8888"))
121         extensions->ensureEnabled("GL_EXT_texture_format_BGRA8888");
122     else
123         return false;
124
125     if (extensions->supports("GL_EXT_read_format_bgra"))
126         extensions->ensureEnabled("GL_EXT_read_format_bgra");
127     else
128         return false;
129
130     if (!context->grContext())
131         return false;
132
133     return true;
134 }
135
136 bool needsLionIOSurfaceReadbackWorkaround()
137 {
138 #if OS(DARWIN)
139     static SInt32 systemVersion = 0;
140     if (!systemVersion) {
141         if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr)
142             return false;
143     }
144
145     return systemVersion >= 0x1070;
146 #else
147     return false;
148 #endif
149 }
150
151 class UnthrottledTextureUploader : public TextureUploader {
152     WTF_MAKE_NONCOPYABLE(UnthrottledTextureUploader);
153 public:
154     static PassOwnPtr<UnthrottledTextureUploader> create()
155     {
156         return adoptPtr(new UnthrottledTextureUploader());
157     }
158     virtual ~UnthrottledTextureUploader() { }
159
160     virtual bool isBusy() { return false; }
161     virtual void beginUploads() { }
162     virtual void endUploads() { }
163     virtual void uploadTexture(CCGraphicsContext* context, LayerTextureUpdater::Texture* texture, TextureAllocator* allocator, const IntRect sourceRect, const IntRect destRect) { texture->updateRect(context, allocator, sourceRect, destRect); }
164
165 protected:
166     UnthrottledTextureUploader() { }
167 };
168
169 } // anonymous namespace
170
171 class LayerRendererSwapBuffersCompleteCallbackAdapter : public Extensions3DChromium::SwapBuffersCompleteCallbackCHROMIUM {
172 public:
173     static PassOwnPtr<LayerRendererSwapBuffersCompleteCallbackAdapter> create(LayerRendererChromium* layerRenderer)
174     {
175         return adoptPtr(new LayerRendererSwapBuffersCompleteCallbackAdapter(layerRenderer));
176     }
177     virtual ~LayerRendererSwapBuffersCompleteCallbackAdapter() { }
178
179     virtual void onSwapBuffersComplete()
180     {
181         m_layerRenderer->onSwapBuffersComplete();
182     }
183
184 private:
185     explicit LayerRendererSwapBuffersCompleteCallbackAdapter(LayerRendererChromium* layerRenderer)
186     {
187         m_layerRenderer = layerRenderer;
188     }
189
190     LayerRendererChromium* m_layerRenderer;
191 };
192
193 class LayerRendererGpuMemoryAllocationChangedCallbackAdapter : public Extensions3DChromium::GpuMemoryAllocationChangedCallbackCHROMIUM {
194 public:
195     static PassOwnPtr<LayerRendererGpuMemoryAllocationChangedCallbackAdapter> create(LayerRendererChromium* layerRenderer)
196     {
197         return adoptPtr(new LayerRendererGpuMemoryAllocationChangedCallbackAdapter(layerRenderer));
198     }
199     virtual ~LayerRendererGpuMemoryAllocationChangedCallbackAdapter() { }
200
201     virtual void onGpuMemoryAllocationChanged(Extensions3DChromium::GpuMemoryAllocationCHROMIUM allocation)
202     {
203         // FIXME: This is called on the main thread in single threaded mode, but we expect it on the impl thread.
204         if (m_bindToImplThread) {
205           ASSERT(CCProxy::isMainThread());
206           DebugScopedSetImplThread impl;
207           onGpuMemoryAllocationChangedOnImpl(allocation);
208         } else {
209           ASSERT(CCProxy::isImplThread());
210           onGpuMemoryAllocationChangedOnImpl(allocation);
211         }
212     }
213
214 private:
215     explicit LayerRendererGpuMemoryAllocationChangedCallbackAdapter(LayerRendererChromium* layerRenderer)
216         : m_layerRenderer(layerRenderer), m_bindToImplThread(!CCProxy::hasImplThread())
217     {
218     }
219
220     void onGpuMemoryAllocationChangedOnImpl(Extensions3DChromium::GpuMemoryAllocationCHROMIUM allocation)
221     {
222         ASSERT(CCProxy::isImplThread());
223         if (!allocation.suggestHaveBackbuffer)
224             m_layerRenderer->discardFramebuffer();
225         else
226             m_layerRenderer->ensureFramebuffer();
227         m_layerRenderer->m_client->setContentsMemoryAllocationLimitBytes(allocation.gpuResourceSizeInBytes);
228     }
229
230     LayerRendererChromium* m_layerRenderer;
231     bool m_bindToImplThread;
232 };
233
234 PassOwnPtr<LayerRendererChromium> LayerRendererChromium::create(CCRendererClient* client, PassRefPtr<GraphicsContext3D> context, TextureUploaderOption textureUploaderSetting)
235 {
236     OwnPtr<LayerRendererChromium> layerRenderer(adoptPtr(new LayerRendererChromium(client, context, textureUploaderSetting)));
237     if (!layerRenderer->initialize())
238         return nullptr;
239
240     return layerRenderer.release();
241 }
242
243 LayerRendererChromium::LayerRendererChromium(CCRendererClient* client,
244                                              PassRefPtr<GraphicsContext3D> context,
245                                              TextureUploaderOption textureUploaderSetting)
246     : CCRenderer(client)
247     , m_currentRenderPass(0)
248     , m_currentManagedTexture(0)
249     , m_offscreenFramebufferId(0)
250     , m_sharedGeometryQuad(FloatRect(-0.5f, -0.5f, 1.0f, 1.0f))
251     , m_context(context)
252     , m_defaultRenderPass(0)
253     , m_isViewportChanged(false)
254     , m_isFramebufferDiscarded(false)
255     , m_textureUploaderSetting(textureUploaderSetting)
256 {
257     ASSERT(m_context.get());
258 }
259
260 class ContextLostCallbackAdapter : public GraphicsContext3D::ContextLostCallback {
261 public:
262     static PassOwnPtr<ContextLostCallbackAdapter> create(CCRendererClient* client)
263     {
264         return adoptPtr(new ContextLostCallbackAdapter(client));
265     }
266
267     virtual void onContextLost()
268     {
269         m_client->didLoseContext();
270     }
271
272 private:
273     explicit ContextLostCallbackAdapter(CCRendererClient* client)
274         : m_client(client) { }
275
276     CCRendererClient* m_client;
277 };
278
279 bool LayerRendererChromium::initialize()
280 {
281     if (!m_context->makeContextCurrent())
282         return false;
283
284     m_context->setContextLostCallback(ContextLostCallbackAdapter::create(m_client));
285
286     if (settings().acceleratePainting && contextSupportsAcceleratedPainting(m_context.get()))
287         m_capabilities.usingAcceleratedPainting = true;
288
289     WebCore::Extensions3D* extensions = m_context->getExtensions();
290     m_capabilities.contextHasCachedFrontBuffer = extensions->supports("GL_CHROMIUM_front_buffer_cached");
291     if (m_capabilities.contextHasCachedFrontBuffer)
292         extensions->ensureEnabled("GL_CHROMIUM_front_buffer_cached");
293
294     m_capabilities.usingPartialSwap = settings().partialSwapEnabled && extensions->supports("GL_CHROMIUM_post_sub_buffer");
295     if (m_capabilities.usingPartialSwap)
296         extensions->ensureEnabled("GL_CHROMIUM_post_sub_buffer");
297
298     m_capabilities.usingMapSub = extensions->supports("GL_CHROMIUM_map_sub");
299     if (m_capabilities.usingMapSub)
300         extensions->ensureEnabled("GL_CHROMIUM_map_sub");
301
302     // Use the swapBuffers callback only with the threaded proxy.
303     if (CCProxy::hasImplThread())
304         m_capabilities.usingSwapCompleteCallback = extensions->supports("GL_CHROMIUM_swapbuffers_complete_callback");
305     if (m_capabilities.usingSwapCompleteCallback) {
306         extensions->ensureEnabled("GL_CHROMIUM_swapbuffers_complete_callback");
307         Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(extensions);
308         extensions3DChromium->setSwapBuffersCompleteCallbackCHROMIUM(LayerRendererSwapBuffersCompleteCallbackAdapter::create(this));
309     }
310
311     if (extensions->supports("GL_EXT_texture_format_BGRA8888"))
312         extensions->ensureEnabled("GL_EXT_texture_format_BGRA8888");
313
314     m_capabilities.usingSetVisibility = extensions->supports("GL_CHROMIUM_set_visibility");
315     if (m_capabilities.usingSetVisibility)
316         extensions->ensureEnabled("GL_CHROMIUM_set_visibility");
317
318     if (extensions->supports("GL_CHROMIUM_iosurface")) {
319         ASSERT(extensions->supports("GL_ARB_texture_rectangle"));
320         extensions->ensureEnabled("GL_ARB_texture_rectangle");
321         extensions->ensureEnabled("GL_CHROMIUM_iosurface");
322     }
323
324     m_capabilities.usingTextureUsageHint = extensions->supports("GL_ANGLE_texture_usage");
325     if (m_capabilities.usingTextureUsageHint)
326         extensions->ensureEnabled("GL_ANGLE_texture_usage");
327
328     m_capabilities.usingTextureStorageExtension = extensions->supports("GL_EXT_texture_storage");
329     if (m_capabilities.usingTextureStorageExtension)
330         extensions->ensureEnabled("GL_EXT_texture_storage");
331
332     m_capabilities.usingGpuMemoryManager = extensions->supports("GL_CHROMIUM_gpu_memory_manager");
333     if (m_capabilities.usingGpuMemoryManager) {
334         extensions->ensureEnabled("GL_CHROMIUM_gpu_memory_manager");
335         Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(extensions);
336         extensions3DChromium->setGpuMemoryAllocationChangedCallbackCHROMIUM(LayerRendererGpuMemoryAllocationChangedCallbackAdapter::create(this));
337     } else {
338         m_client->setContentsMemoryAllocationLimitBytes(TextureManager::highLimitBytes(viewportSize()));
339     }
340
341     m_capabilities.usingDiscardFramebuffer = extensions->supports("GL_CHROMIUM_discard_framebuffer");
342     if (m_capabilities.usingDiscardFramebuffer)
343         extensions->ensureEnabled("GL_CHROMIUM_discard_framebuffer");
344
345     GLC(m_context, m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_capabilities.maxTextureSize));
346     m_capabilities.bestTextureFormat = PlatformColor::bestTextureFormat(m_context.get());
347
348     if (!initializeSharedObjects())
349         return false;
350
351     // Make sure the viewport and context gets initialized, even if it is to zero.
352     viewportChanged();
353     return true;
354 }
355
356 LayerRendererChromium::~LayerRendererChromium()
357 {
358     ASSERT(CCProxy::isImplThread());
359     Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(m_context->getExtensions());
360     extensions3DChromium->setSwapBuffersCompleteCallbackCHROMIUM(nullptr);
361     extensions3DChromium->setGpuMemoryAllocationChangedCallbackCHROMIUM(nullptr);
362     cleanupSharedObjects();
363 }
364
365 GraphicsContext3D* LayerRendererChromium::context()
366 {
367     return m_context.get();
368 }
369
370 void LayerRendererChromium::debugGLCall(GraphicsContext3D* context, const char* command, const char* file, int line)
371 {
372     unsigned long error = context->getError();
373     if (error != GraphicsContext3D::NO_ERROR)
374         LOG_ERROR("GL command failed: File: %s\n\tLine %d\n\tcommand: %s, error %x\n", file, line, command, static_cast<int>(error));
375 }
376
377 void LayerRendererChromium::setVisible(bool visible)
378 {
379     if (!visible)
380         releaseRenderPassTextures();
381
382     // TODO: Replace setVisibilityCHROMIUM with an extension to explicitly manage front/backbuffers
383     // crbug.com/116049
384     if (m_capabilities.usingSetVisibility) {
385         Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(m_context->getExtensions());
386         extensions3DChromium->setVisibilityCHROMIUM(visible);
387     }
388 }
389
390 void LayerRendererChromium::releaseRenderPassTextures()
391 {
392     if (m_implTextureManager)
393         m_implTextureManager->evictAndDeleteAllTextures(m_implTextureAllocator.get());
394 }
395
396 void LayerRendererChromium::viewportChanged()
397 {
398     m_isViewportChanged = true;
399
400     // Reset the current RenderPass to force an update of the viewport and
401     // projection matrix next time useRenderPass is called.
402     m_currentRenderPass = 0;
403 }
404
405 void LayerRendererChromium::clearRenderPass(const CCRenderPass* renderPass, const FloatRect& framebufferDamageRect)
406 {
407     // On DEBUG builds, opaque render passes are cleared to blue to easily see regions that were not drawn on the screen. If we
408     // are using partial swap / scissor optimization, then the surface should only
409     // clear the damaged region, so that we don't accidentally clear un-changed portions
410     // of the screen.
411
412     if (renderPass->hasTransparentBackground())
413         GLC(m_context, m_context->clearColor(0, 0, 0, 0));
414     else
415         GLC(m_context, m_context->clearColor(0, 0, 1, 1));
416
417     if (m_capabilities.usingPartialSwap)
418         setScissorToRect(enclosingIntRect(framebufferDamageRect));
419     else
420         GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
421
422 #if defined(NDEBUG)
423     if (renderPass->hasTransparentBackground())
424 #endif
425         m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
426
427     GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST));
428 }
429
430 void LayerRendererChromium::beginDrawingFrame(const CCRenderPass* rootRenderPass)
431 {
432     // FIXME: Remove this once framebuffer is automatically recreated on first use
433     ensureFramebuffer();
434
435     m_defaultRenderPass = rootRenderPass;
436     ASSERT(m_defaultRenderPass);
437
438     size_t contentsMemoryUseBytes = m_contentsTextureAllocator->currentMemoryUseBytes();
439     size_t maxLimit = TextureManager::highLimitBytes(viewportSize());
440     size_t newLimit = (maxLimit > contentsMemoryUseBytes) ? maxLimit - contentsMemoryUseBytes : 0;
441     m_implTextureManager->setMaxMemoryLimitBytes(newLimit);
442
443     if (viewportSize().isEmpty())
444         return;
445
446     TRACE_EVENT("LayerRendererChromium::drawLayers", this, 0);
447     if (m_isViewportChanged) {
448         // Only reshape when we know we are going to draw. Otherwise, the reshape
449         // can leave the window at the wrong size if we never draw and the proper
450         // viewport size is never set.
451         m_isViewportChanged = false;
452         m_context->reshape(viewportWidth(), viewportHeight());
453     }
454
455     makeContextCurrent();
456     // Bind the common vertex attributes used for drawing all the layers.
457     m_sharedGeometry->prepareForDraw();
458
459     GLC(m_context, m_context->disable(GraphicsContext3D::DEPTH_TEST));
460     GLC(m_context, m_context->disable(GraphicsContext3D::CULL_FACE));
461     GLC(m_context, m_context->colorMask(true, true, true, true));
462     GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
463     GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
464 }
465
466 void LayerRendererChromium::doNoOp()
467 {
468     GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
469     GLC(m_context, m_context->flush());
470 }
471
472 void LayerRendererChromium::drawRenderPass(const CCRenderPass* renderPass, const FloatRect& framebufferDamageRect)
473 {
474     if (!useRenderPass(renderPass))
475         return;
476
477     clearRenderPass(renderPass, framebufferDamageRect);
478
479     const CCQuadList& quadList = renderPass->quadList();
480     for (CCQuadList::constBackToFrontIterator it = quadList.backToFrontBegin(); it != quadList.backToFrontEnd(); ++it)
481         drawQuad(it->get());
482 }
483
484 void LayerRendererChromium::drawQuad(const CCDrawQuad* quad)
485 {
486     IntRect scissorRect = quad->scissorRect();
487
488     ASSERT(!scissorRect.isEmpty());
489     if (scissorRect.isEmpty())
490         return;
491
492     setScissorToRect(scissorRect);
493
494     if (quad->needsBlending())
495         GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
496     else
497         GLC(m_context, m_context->disable(GraphicsContext3D::BLEND));
498
499     switch (quad->material()) {
500     case CCDrawQuad::Invalid:
501         ASSERT_NOT_REACHED();
502         break;
503     case CCDrawQuad::Checkerboard:
504         drawCheckerboardQuad(quad->toCheckerboardDrawQuad());
505         break;
506     case CCDrawQuad::DebugBorder:
507         drawDebugBorderQuad(quad->toDebugBorderDrawQuad());
508         break;
509     case CCDrawQuad::IOSurfaceContent:
510         drawIOSurfaceQuad(quad->toIOSurfaceDrawQuad());
511         break;
512     case CCDrawQuad::RenderPass:
513         drawRenderPassQuad(quad->toRenderPassDrawQuad());
514         break;
515     case CCDrawQuad::SolidColor:
516         drawSolidColorQuad(quad->toSolidColorDrawQuad());
517         break;
518     case CCDrawQuad::TextureContent:
519         drawTextureQuad(quad->toTextureDrawQuad());
520         break;
521     case CCDrawQuad::TiledContent:
522         drawTileQuad(quad->toTileDrawQuad());
523         break;
524     case CCDrawQuad::VideoContent:
525         drawVideoQuad(quad->toVideoDrawQuad());
526         break;
527     }
528 }
529
530 void LayerRendererChromium::drawCheckerboardQuad(const CCCheckerboardDrawQuad* quad)
531 {
532     const TileCheckerboardProgram* program = tileCheckerboardProgram();
533     ASSERT(program && program->initialized());
534     GLC(context(), context()->useProgram(program->program()));
535
536     IntRect tileRect = quad->quadRect();
537     WebTransformationMatrix tileTransform = quad->quadTransform();
538     tileTransform.translate(tileRect.x() + tileRect.width() / 2.0, tileRect.y() + tileRect.height() / 2.0);
539
540     float texOffsetX = tileRect.x();
541     float texOffsetY = tileRect.y();
542     float texScaleX = tileRect.width();
543     float texScaleY = tileRect.height();
544     GLC(context(), context()->uniform4f(program->fragmentShader().texTransformLocation(), texOffsetX, texOffsetY, texScaleX, texScaleY));
545
546     const int checkerboardWidth = 16;
547     float frequency = 1.0 / checkerboardWidth;
548
549     GLC(context(), context()->uniform1f(program->fragmentShader().frequencyLocation(), frequency));
550
551     float opacity = quad->opacity();
552     drawTexturedQuad(tileTransform,
553                      tileRect.width(), tileRect.height(), opacity, FloatQuad(),
554                      program->vertexShader().matrixLocation(),
555                      program->fragmentShader().alphaLocation(), -1);
556 }
557
558 void LayerRendererChromium::drawDebugBorderQuad(const CCDebugBorderDrawQuad* quad)
559 {
560     static float glMatrix[16];
561     const SolidColorProgram* program = solidColorProgram();
562     ASSERT(program && program->initialized());
563     GLC(context(), context()->useProgram(program->program()));
564
565     const IntRect& layerRect = quad->quadRect();
566     WebTransformationMatrix renderMatrix = quad->quadTransform();
567     renderMatrix.translate(0.5 * layerRect.width() + layerRect.x(), 0.5 * layerRect.height() + layerRect.y());
568     renderMatrix.scaleNonUniform(layerRect.width(), layerRect.height());
569     LayerRendererChromium::toGLMatrix(&glMatrix[0], projectionMatrix() * renderMatrix);
570     GLC(context(), context()->uniformMatrix4fv(program->vertexShader().matrixLocation(), 1, false, &glMatrix[0]));
571
572     const Color& color = quad->color();
573     float alpha = color.alpha() / 255.0;
574
575     GLC(context(), context()->uniform4f(program->fragmentShader().colorLocation(), (color.red() / 255.0) * alpha, (color.green() / 255.0) * alpha, (color.blue() / 255.0) * alpha, alpha));
576
577     GLC(context(), context()->lineWidth(quad->width()));
578
579     // The indices for the line are stored in the same array as the triangle indices.
580     GLC(context(), context()->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short)));
581 }
582
583 static inline SkBitmap applyFilters(LayerRendererChromium* layerRenderer, const WebKit::WebFilterOperations& filters, ManagedTexture* sourceTexture)
584 {
585     if (filters.isEmpty())
586         return SkBitmap();
587
588     RefPtr<GraphicsContext3D> filterContext = CCProxy::hasImplThread() ? SharedGraphicsContext3D::getForImplThread() : SharedGraphicsContext3D::get();
589     if (!filterContext)
590         return SkBitmap();
591
592     layerRenderer->context()->flush();
593
594     return CCRenderSurfaceFilters::apply(filters, sourceTexture->textureId(), sourceTexture->size(), filterContext.get());
595 }
596
597 void LayerRendererChromium::drawBackgroundFilters(const CCRenderPassDrawQuad* quad, const WebTransformationMatrix& contentsDeviceTransform)
598 {
599     // This method draws a background filter, which applies a filter to any pixels behind the quad and seen through its background.
600     // The algorithm works as follows:
601     // 1. Compute a bounding box around the pixels that will be visible through the quad.
602     // 2. Read the pixels in the bounding box into a buffer R.
603     // 3. Apply the background filter to R, so that it is applied in the pixels' coordinate space.
604     // 4. Apply the quad's inverse transform to map the pixels in R into the quad's content space. This implicitly
605     // clips R by the content bounds of the quad since the destination texture has bounds matching the quad's content.
606     // 5. Draw the background texture for the contents using the same transform as used to draw the contents itself. This is done
607     // without blending to replace the current background pixels with the new filtered background.
608     // 6. Draw the contents of the quad over drop of the new background with blending, as per usual. The filtered background
609     // pixels will show through any non-opaque pixels in this draws.
610     //
611     // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
612
613     CCRenderSurface* drawingSurface = quad->renderPass()->targetSurface();
614     if (quad->backgroundFilters().isEmpty())
615         return;
616
617     // FIXME: We only allow background filters on an opaque render surface because other surfaces may contain
618     // translucent pixels, and the contents behind those translucent pixels wouldn't have the filter applied.
619     if (m_currentRenderPass->hasTransparentBackground())
620         return;
621     ASSERT(!m_currentManagedTexture);
622
623     // FIXME: Do a single readback for both the surface and replica and cache the filtered results (once filter textures are not reused).
624     IntRect deviceRect = enclosingIntRect(CCMathUtil::mapClippedRect(contentsDeviceTransform, sharedGeometryQuad().boundingBox()));
625
626     int top, right, bottom, left;
627     quad->backgroundFilters().getOutsets(top, right, bottom, left);
628     deviceRect.move(-left, -top);
629     deviceRect.expand(left + right, top + bottom);
630
631     deviceRect.intersect(m_currentRenderPass->framebufferOutputRect());
632
633     OwnPtr<ManagedTexture> deviceBackgroundTexture = ManagedTexture::create(m_implTextureManager.get());
634     if (!getFramebufferTexture(deviceBackgroundTexture.get(), deviceRect))
635         return;
636
637     SkBitmap filteredDeviceBackground = applyFilters(this, quad->backgroundFilters(), deviceBackgroundTexture.get());
638     if (!filteredDeviceBackground.getTexture())
639         return;
640
641     GrTexture* texture = reinterpret_cast<GrTexture*>(filteredDeviceBackground.getTexture());
642     int filteredDeviceBackgroundTextureId = texture->getTextureHandle();
643
644     if (!drawingSurface->prepareBackgroundTexture(this))
645         return;
646
647     const CCRenderPass* targetRenderPass = m_currentRenderPass;
648     if (useManagedTexture(drawingSurface->backgroundTexture(), quad->quadRect())) {
649         // Copy the readback pixels from device to the background texture for the surface.
650         WebTransformationMatrix deviceToFramebufferTransform;
651         deviceToFramebufferTransform.translate(quad->quadRect().width() / 2.0, quad->quadRect().height() / 2.0);
652         deviceToFramebufferTransform.scale3d(quad->quadRect().width(), quad->quadRect().height(), 1);
653         deviceToFramebufferTransform.multiply(contentsDeviceTransform.inverse());
654         deviceToFramebufferTransform.translate(deviceRect.width() / 2.0, deviceRect.height() / 2.0);
655         deviceToFramebufferTransform.translate(deviceRect.x(), deviceRect.y());
656
657         copyTextureToFramebuffer(filteredDeviceBackgroundTextureId, deviceRect.size(), deviceToFramebufferTransform);
658
659         useRenderPass(targetRenderPass);
660     }
661 }
662
663 void LayerRendererChromium::drawRenderPassQuad(const CCRenderPassDrawQuad* quad)
664 {
665     // The replica is always drawn first, so free after drawing the contents.
666     bool shouldReleaseTextures = !quad->isReplica();
667
668     CCRenderSurface* drawingSurface = quad->renderPass()->targetSurface();
669
670     WebTransformationMatrix renderTransform = quad->layerTransform();
671     // Apply a scaling factor to size the quad from 1x1 to its intended size.
672     renderTransform.scale3d(quad->quadRect().width(), quad->quadRect().height(), 1);
673     WebTransformationMatrix contentsDeviceTransform = WebTransformationMatrix(windowMatrix() * projectionMatrix() * renderTransform).to2dTransform();
674
675     // Can only draw surface if device matrix is invertible.
676     if (!contentsDeviceTransform.isInvertible() || !drawingSurface->hasValidContentsTexture()) {
677         if (shouldReleaseTextures) {
678             drawingSurface->releaseBackgroundTexture();
679             drawingSurface->releaseContentsTexture();
680         }
681         return;
682     }
683
684     drawBackgroundFilters(quad, contentsDeviceTransform);
685
686     // FIXME: Cache this value so that we don't have to do it for both the surface and its replica.
687     // Apply filters to the contents texture.
688     SkBitmap filterBitmap = applyFilters(this, quad->filters(), drawingSurface->contentsTexture());
689     int contentsTextureId = drawingSurface->contentsTexture()->textureId();
690     if (filterBitmap.getTexture()) {
691         GrTexture* texture = reinterpret_cast<GrTexture*>(filterBitmap.getTexture());
692         contentsTextureId = texture->getTextureHandle();
693     }
694
695     // Draw the background texture if there is one.
696     if (drawingSurface->hasValidBackgroundTexture())
697         copyTextureToFramebuffer(drawingSurface->backgroundTexture()->textureId(), quad->quadRect().size(), quad->layerTransform());
698
699     FloatQuad deviceQuad = contentsDeviceTransform.mapQuad(sharedGeometryQuad());
700     CCLayerQuad deviceLayerBounds = CCLayerQuad(FloatQuad(deviceQuad.boundingBox()));
701     CCLayerQuad deviceLayerEdges = CCLayerQuad(deviceQuad);
702
703     // Use anti-aliasing programs only when necessary.
704     bool useAA = (!deviceQuad.isRectilinear() || !deviceQuad.boundingBox().isExpressibleAsIntRect());
705     if (useAA) {
706         deviceLayerBounds.inflateAntiAliasingDistance();
707         deviceLayerEdges.inflateAntiAliasingDistance();
708     }
709
710     bool useMask = quad->maskTextureId();
711
712     // FIXME: use the backgroundTexture and blend the background in with this draw instead of having a separate copy of the background texture.
713
714     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
715     context()->bindTexture(GraphicsContext3D::TEXTURE_2D, contentsTextureId);
716
717     int shaderQuadLocation = -1;
718     int shaderEdgeLocation = -1;
719     int shaderMaskSamplerLocation = -1;
720     int shaderMatrixLocation = -1;
721     int shaderAlphaLocation = -1;
722     if (useAA && useMask) {
723         const RenderPassMaskProgramAA* program = renderPassMaskProgramAA();
724         GLC(context(), context()->useProgram(program->program()));
725         GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
726
727         shaderQuadLocation = program->vertexShader().pointLocation();
728         shaderEdgeLocation = program->fragmentShader().edgeLocation();
729         shaderMaskSamplerLocation = program->fragmentShader().maskSamplerLocation();
730         shaderMatrixLocation = program->vertexShader().matrixLocation();
731         shaderAlphaLocation = program->fragmentShader().alphaLocation();
732     } else if (!useAA && useMask) {
733         const RenderPassMaskProgram* program = renderPassMaskProgram();
734         GLC(context(), context()->useProgram(program->program()));
735         GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
736
737         shaderMaskSamplerLocation = program->fragmentShader().maskSamplerLocation();
738         shaderMatrixLocation = program->vertexShader().matrixLocation();
739         shaderAlphaLocation = program->fragmentShader().alphaLocation();
740     } else if (useAA && !useMask) {
741         const RenderPassProgramAA* program = renderPassProgramAA();
742         GLC(context(), context()->useProgram(program->program()));
743         GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
744
745         shaderQuadLocation = program->vertexShader().pointLocation();
746         shaderEdgeLocation = program->fragmentShader().edgeLocation();
747         shaderMatrixLocation = program->vertexShader().matrixLocation();
748         shaderAlphaLocation = program->fragmentShader().alphaLocation();
749     } else {
750         const RenderPassProgram* program = renderPassProgram();
751         GLC(context(), context()->useProgram(program->program()));
752         GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
753
754         shaderMatrixLocation = program->vertexShader().matrixLocation();
755         shaderAlphaLocation = program->fragmentShader().alphaLocation();
756     }
757
758     if (shaderMaskSamplerLocation != -1) {
759         GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE1));
760         GLC(context(), context()->uniform1i(shaderMaskSamplerLocation, 1));
761         context()->bindTexture(GraphicsContext3D::TEXTURE_2D, quad->maskTextureId());
762         GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
763     }
764
765     if (shaderEdgeLocation != -1) {
766         float edge[24];
767         deviceLayerEdges.toFloatArray(edge);
768         deviceLayerBounds.toFloatArray(&edge[12]);
769         GLC(context(), context()->uniform3fv(shaderEdgeLocation, 8, edge));
770     }
771
772     // Map device space quad to surface space.
773     FloatQuad surfaceQuad = contentsDeviceTransform.inverse().mapQuad(deviceLayerEdges.floatQuad());
774
775     drawTexturedQuad(quad->layerTransform(), quad->quadRect().width(), quad->quadRect().height(), quad->opacity(), surfaceQuad,
776                      shaderMatrixLocation, shaderAlphaLocation, shaderQuadLocation);
777
778     if (shouldReleaseTextures) {
779         drawingSurface->releaseBackgroundTexture();
780         drawingSurface->releaseContentsTexture();
781     }
782 }
783
784 void LayerRendererChromium::drawSolidColorQuad(const CCSolidColorDrawQuad* quad)
785 {
786     const SolidColorProgram* program = solidColorProgram();
787     GLC(context(), context()->useProgram(program->program()));
788
789     IntRect tileRect = quad->quadRect();
790
791     WebTransformationMatrix tileTransform = quad->quadTransform();
792     tileTransform.translate(tileRect.x() + tileRect.width() / 2.0, tileRect.y() + tileRect.height() / 2.0);
793
794     const Color& color = quad->color();
795     float opacity = quad->opacity();
796     float alpha = (color.alpha() / 255.0) * opacity;
797
798     GLC(context(), context()->uniform4f(program->fragmentShader().colorLocation(), (color.red() / 255.0) * alpha, (color.green() / 255.0) * alpha, (color.blue() / 255.0) * alpha, alpha));
799
800     drawTexturedQuad(tileTransform,
801                      tileRect.width(), tileRect.height(), 1.0, FloatQuad(),
802                      program->vertexShader().matrixLocation(),
803                      -1, -1);
804 }
805
806 struct TileProgramUniforms {
807     unsigned program;
808     unsigned samplerLocation;
809     unsigned vertexTexTransformLocation;
810     unsigned fragmentTexTransformLocation;
811     unsigned edgeLocation;
812     unsigned matrixLocation;
813     unsigned alphaLocation;
814     unsigned pointLocation;
815 };
816
817 template<class T>
818 static void tileUniformLocation(T program, TileProgramUniforms& uniforms)
819 {
820     uniforms.program = program->program();
821     uniforms.vertexTexTransformLocation = program->vertexShader().vertexTexTransformLocation();
822     uniforms.matrixLocation = program->vertexShader().matrixLocation();
823     uniforms.pointLocation = program->vertexShader().pointLocation();
824
825     uniforms.samplerLocation = program->fragmentShader().samplerLocation();
826     uniforms.alphaLocation = program->fragmentShader().alphaLocation();
827     uniforms.fragmentTexTransformLocation = program->fragmentShader().fragmentTexTransformLocation();
828     uniforms.edgeLocation = program->fragmentShader().edgeLocation();
829 }
830
831 void LayerRendererChromium::drawTileQuad(const CCTileDrawQuad* quad)
832 {
833     const IntRect& tileRect = quad->quadVisibleRect();
834
835     FloatRect clampRect(tileRect);
836     // Clamp texture coordinates to avoid sampling outside the layer
837     // by deflating the tile region half a texel or half a texel
838     // minus epsilon for one pixel layers. The resulting clamp region
839     // is mapped to the unit square by the vertex shader and mapped
840     // back to normalized texture coordinates by the fragment shader
841     // after being clamped to 0-1 range.
842     const float epsilon = 1 / 1024.0f;
843     float clampX = min(0.5, clampRect.width() / 2.0 - epsilon);
844     float clampY = min(0.5, clampRect.height() / 2.0 - epsilon);
845     clampRect.inflateX(-clampX);
846     clampRect.inflateY(-clampY);
847     FloatSize clampOffset = clampRect.minXMinYCorner() - FloatRect(tileRect).minXMinYCorner();
848
849     FloatPoint textureOffset = quad->textureOffset() + clampOffset +
850                                IntPoint(quad->quadVisibleRect().location() - quad->quadRect().location());
851
852     // Map clamping rectangle to unit square.
853     float vertexTexTranslateX = -clampRect.x() / clampRect.width();
854     float vertexTexTranslateY = -clampRect.y() / clampRect.height();
855     float vertexTexScaleX = tileRect.width() / clampRect.width();
856     float vertexTexScaleY = tileRect.height() / clampRect.height();
857
858     // Map to normalized texture coordinates.
859     const IntSize& textureSize = quad->textureSize();
860     float fragmentTexTranslateX = textureOffset.x() / textureSize.width();
861     float fragmentTexTranslateY = textureOffset.y() / textureSize.height();
862     float fragmentTexScaleX = clampRect.width() / textureSize.width();
863     float fragmentTexScaleY = clampRect.height() / textureSize.height();
864
865
866     FloatQuad localQuad;
867     WebTransformationMatrix deviceTransform = WebTransformationMatrix(windowMatrix() * projectionMatrix() * quad->quadTransform()).to2dTransform();
868     if (!deviceTransform.isInvertible())
869         return;
870
871     bool clipped = false;
872     FloatQuad deviceLayerQuad = CCMathUtil::mapQuad(deviceTransform, FloatQuad(quad->layerRect()), clipped);
873
874     TileProgramUniforms uniforms;
875     // For now, we simply skip anti-aliasing with the quad is clipped. This only happens
876     // on perspective transformed layers that go partially behind the camera.
877     if (quad->isAntialiased() && !clipped) {
878         if (quad->swizzleContents())
879             tileUniformLocation(tileProgramSwizzleAA(), uniforms);
880         else
881             tileUniformLocation(tileProgramAA(), uniforms);
882     } else {
883         if (quad->needsBlending()) {
884             if (quad->swizzleContents())
885                 tileUniformLocation(tileProgramSwizzle(), uniforms);
886             else
887                 tileUniformLocation(tileProgram(), uniforms);
888         } else {
889             if (quad->swizzleContents())
890                 tileUniformLocation(tileProgramSwizzleOpaque(), uniforms);
891             else
892                 tileUniformLocation(tileProgramOpaque(), uniforms);
893         }
894     }
895
896     GLC(context(), context()->useProgram(uniforms.program));
897     GLC(context(), context()->uniform1i(uniforms.samplerLocation, 0));
898     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
899     GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, quad->textureId()));
900     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, quad->textureFilter()));
901     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, quad->textureFilter()));
902
903
904     if (!clipped && quad->isAntialiased()) {
905
906         CCLayerQuad deviceLayerBounds = CCLayerQuad(FloatQuad(deviceLayerQuad.boundingBox()));
907         deviceLayerBounds.inflateAntiAliasingDistance();
908
909         CCLayerQuad deviceLayerEdges = CCLayerQuad(deviceLayerQuad);
910         deviceLayerEdges.inflateAntiAliasingDistance();
911
912         float edge[24];
913         deviceLayerEdges.toFloatArray(edge);
914         deviceLayerBounds.toFloatArray(&edge[12]);
915         GLC(context(), context()->uniform3fv(uniforms.edgeLocation, 8, edge));
916
917         GLC(context(), context()->uniform4f(uniforms.vertexTexTransformLocation, vertexTexTranslateX, vertexTexTranslateY, vertexTexScaleX, vertexTexScaleY));
918         GLC(context(), context()->uniform4f(uniforms.fragmentTexTransformLocation, fragmentTexTranslateX, fragmentTexTranslateY, fragmentTexScaleX, fragmentTexScaleY));
919
920         FloatPoint bottomRight(tileRect.maxX(), tileRect.maxY());
921         FloatPoint bottomLeft(tileRect.x(), tileRect.maxY());
922         FloatPoint topLeft(tileRect.x(), tileRect.y());
923         FloatPoint topRight(tileRect.maxX(), tileRect.y());
924
925         // Map points to device space.
926         bottomRight = deviceTransform.mapPoint(bottomRight);
927         bottomLeft = deviceTransform.mapPoint(bottomLeft);
928         topLeft = deviceTransform.mapPoint(topLeft);
929         topRight = deviceTransform.mapPoint(topRight);
930
931         CCLayerQuad::Edge bottomEdge(bottomRight, bottomLeft);
932         CCLayerQuad::Edge leftEdge(bottomLeft, topLeft);
933         CCLayerQuad::Edge topEdge(topLeft, topRight);
934         CCLayerQuad::Edge rightEdge(topRight, bottomRight);
935
936         // Only apply anti-aliasing to edges not clipped during culling.
937         if (quad->topEdgeAA() && tileRect.y() == quad->quadRect().y())
938             topEdge = deviceLayerEdges.top();
939         if (quad->leftEdgeAA() && tileRect.x() == quad->quadRect().x())
940             leftEdge = deviceLayerEdges.left();
941         if (quad->rightEdgeAA() && tileRect.maxX() == quad->quadRect().maxX())
942             rightEdge = deviceLayerEdges.right();
943         if (quad->bottomEdgeAA() && tileRect.maxY() == quad->quadRect().maxY())
944             bottomEdge = deviceLayerEdges.bottom();
945
946         float sign = FloatQuad(tileRect).isCounterclockwise() ? -1 : 1;
947         bottomEdge.scale(sign);
948         leftEdge.scale(sign);
949         topEdge.scale(sign);
950         rightEdge.scale(sign);
951
952         // Create device space quad.
953         CCLayerQuad deviceQuad(leftEdge, topEdge, rightEdge, bottomEdge);
954
955         // Map quad to layer space.
956         WebTransformationMatrix inverseDeviceTransform = deviceTransform.inverse();
957         localQuad = inverseDeviceTransform.mapQuad(deviceQuad.floatQuad());
958     } else {
959         // Move fragment shader transform to vertex shader. We can do this while
960         // still producing correct results as fragmentTexTransformLocation
961         // should always be non-negative when tiles are transformed in a way
962         // that could result in sampling outside the layer.
963         vertexTexScaleX *= fragmentTexScaleX;
964         vertexTexScaleY *= fragmentTexScaleY;
965         vertexTexTranslateX *= fragmentTexScaleX;
966         vertexTexTranslateY *= fragmentTexScaleY;
967         vertexTexTranslateX += fragmentTexTranslateX;
968         vertexTexTranslateY += fragmentTexTranslateY;
969
970         GLC(context(), context()->uniform4f(uniforms.vertexTexTransformLocation, vertexTexTranslateX, vertexTexTranslateY, vertexTexScaleX, vertexTexScaleY));
971
972         localQuad = FloatRect(tileRect);
973     }
974
975     // Normalize to tileRect.
976     localQuad.scale(1.0f / tileRect.width(), 1.0f / tileRect.height());
977
978     drawTexturedQuad(quad->quadTransform(), tileRect.width(), tileRect.height(), quad->opacity(), localQuad, uniforms.matrixLocation, uniforms.alphaLocation, uniforms.pointLocation);
979 }
980
981 void LayerRendererChromium::drawYUV(const CCVideoDrawQuad* quad)
982 {
983     const VideoYUVProgram* program = videoYUVProgram();
984     ASSERT(program && program->initialized());
985
986     const CCVideoLayerImpl::Texture& yTexture = quad->textures()[WebKit::WebVideoFrame::yPlane];
987     const CCVideoLayerImpl::Texture& uTexture = quad->textures()[WebKit::WebVideoFrame::uPlane];
988     const CCVideoLayerImpl::Texture& vTexture = quad->textures()[WebKit::WebVideoFrame::vPlane];
989
990     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE1));
991     GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, yTexture.m_texture->textureId()));
992     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE2));
993     GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, uTexture.m_texture->textureId()));
994     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE3));
995     GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, vTexture.m_texture->textureId()));
996
997     GLC(context(), context()->useProgram(program->program()));
998
999     float yWidthScaleFactor = static_cast<float>(yTexture.m_visibleSize.width()) / yTexture.m_texture->size().width();
1000     // Arbitrarily take the u sizes because u and v dimensions are identical.
1001     float uvWidthScaleFactor = static_cast<float>(uTexture.m_visibleSize.width()) / uTexture.m_texture->size().width();
1002     GLC(context(), context()->uniform1f(program->vertexShader().yWidthScaleFactorLocation(), yWidthScaleFactor));
1003     GLC(context(), context()->uniform1f(program->vertexShader().uvWidthScaleFactorLocation(), uvWidthScaleFactor));
1004
1005     GLC(context(), context()->uniform1i(program->fragmentShader().yTextureLocation(), 1));
1006     GLC(context(), context()->uniform1i(program->fragmentShader().uTextureLocation(), 2));
1007     GLC(context(), context()->uniform1i(program->fragmentShader().vTextureLocation(), 3));
1008
1009     GLC(context(), context()->uniformMatrix3fv(program->fragmentShader().ccMatrixLocation(), 1, 0, const_cast<float*>(CCVideoLayerImpl::yuv2RGB)));
1010     GLC(context(), context()->uniform3fv(program->fragmentShader().yuvAdjLocation(), 1, const_cast<float*>(CCVideoLayerImpl::yuvAdjust)));
1011
1012     const IntSize& bounds = quad->quadRect().size();
1013     drawTexturedQuad(quad->layerTransform(), bounds.width(), bounds.height(), quad->opacity(), FloatQuad(),
1014                                     program->vertexShader().matrixLocation(),
1015                                     program->fragmentShader().alphaLocation(),
1016                                     -1);
1017
1018     // Reset active texture back to texture 0.
1019     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
1020 }
1021
1022 template<class Program>
1023 void LayerRendererChromium::drawSingleTextureVideoQuad(const CCVideoDrawQuad* quad, Program* program, float widthScaleFactor, Platform3DObject textureId, GC3Denum target)
1024 {
1025     ASSERT(program && program->initialized());
1026
1027     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
1028     GLC(context(), context()->bindTexture(target, textureId));
1029
1030     GLC(context(), context()->useProgram(program->program()));
1031     GLC(context(), context()->uniform4f(program->vertexShader().texTransformLocation(), 0, 0, widthScaleFactor, 1));
1032     GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
1033
1034     const IntSize& bounds = quad->quadRect().size();
1035     drawTexturedQuad(quad->layerTransform(), bounds.width(), bounds.height(), quad->opacity(), sharedGeometryQuad(),
1036                                     program->vertexShader().matrixLocation(),
1037                                     program->fragmentShader().alphaLocation(),
1038                                     -1);
1039 }
1040
1041 void LayerRendererChromium::drawRGBA(const CCVideoDrawQuad* quad)
1042 {
1043     const TextureProgram* program = textureProgram();
1044     const CCVideoLayerImpl::Texture& texture = quad->textures()[WebKit::WebVideoFrame::rgbPlane];
1045     float widthScaleFactor = static_cast<float>(texture.m_visibleSize.width()) / texture.m_texture->size().width();
1046     drawSingleTextureVideoQuad(quad, program, widthScaleFactor, texture.m_texture->textureId(), GraphicsContext3D::TEXTURE_2D);
1047 }
1048
1049 void LayerRendererChromium::drawNativeTexture2D(const CCVideoDrawQuad* quad)
1050 {
1051     drawSingleTextureVideoQuad(quad, textureProgram(), 1, quad->frame()->textureId(), GraphicsContext3D::TEXTURE_2D);
1052 }
1053
1054 void LayerRendererChromium::drawStreamTexture(const CCVideoDrawQuad* quad)
1055 {
1056     ASSERT(context()->getExtensions()->supports("GL_OES_EGL_image_external") && context()->getExtensions()->isEnabled("GL_OES_EGL_image_external"));
1057
1058     const VideoStreamTextureProgram* program = videoStreamTextureProgram();
1059     GLC(context(), context()->useProgram(program->program()));
1060     ASSERT(quad->matrix());
1061     GLC(context(), context()->uniformMatrix4fv(program->vertexShader().texMatrixLocation(), 1, false, const_cast<float*>(quad->matrix())));
1062
1063     drawSingleTextureVideoQuad(quad, program, 1, quad->frame()->textureId(), Extensions3DChromium::GL_TEXTURE_EXTERNAL_OES);
1064 }
1065
1066 bool LayerRendererChromium::copyFrameToTextures(const CCVideoDrawQuad* quad)
1067 {
1068     const WebKit::WebVideoFrame* frame = quad->frame();
1069
1070     for (unsigned plane = 0; plane < frame->planes(); ++plane)
1071         copyPlaneToTexture(quad, frame->data(plane), plane);
1072
1073     for (unsigned plane = frame->planes(); plane < CCVideoLayerImpl::MaxPlanes; ++plane) {
1074         CCVideoLayerImpl::Texture* texture = &quad->textures()[plane];
1075         texture->m_texture.clear();
1076         texture->m_visibleSize = IntSize();
1077     }
1078     return true;
1079 }
1080
1081 void LayerRendererChromium::copyPlaneToTexture(const CCVideoDrawQuad* quad, const void* plane, int index)
1082 {
1083     CCVideoLayerImpl::Texture& texture = quad->textures()[index];
1084     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(m_context);
1085     texture.m_texture->bindTexture(ccContext.get(), m_implTextureAllocator.get());
1086     GC3Denum format = texture.m_texture->format();
1087     IntSize dimensions = texture.m_texture->size();
1088
1089     void* mem = static_cast<Extensions3DChromium*>(context()->getExtensions())->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, Extensions3DChromium::WRITE_ONLY);
1090     if (mem) {
1091         memcpy(mem, plane, dimensions.width() * dimensions.height());
1092         GLC(context(), static_cast<Extensions3DChromium*>(context()->getExtensions())->unmapTexSubImage2DCHROMIUM(mem));
1093     } else {
1094         // If mapTexSubImage2DCHROMIUM fails, then do the slower texSubImage2D
1095         // upload. This does twice the copies as mapTexSubImage2DCHROMIUM, one
1096         // in the command buffer and another to the texture.
1097         GLC(context(), context()->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, plane));
1098     }
1099 }
1100
1101 void LayerRendererChromium::drawVideoQuad(const CCVideoDrawQuad* quad)
1102 {
1103     ASSERT(CCProxy::isImplThread());
1104
1105     if (!quad->frame())
1106         return;
1107
1108     if (!copyFrameToTextures(quad))
1109         return;
1110
1111     switch (quad->format()) {
1112     case GraphicsContext3D::LUMINANCE:
1113         drawYUV(quad);
1114         break;
1115     case GraphicsContext3D::RGBA:
1116         drawRGBA(quad);
1117         break;
1118     case GraphicsContext3D::TEXTURE_2D:
1119         drawNativeTexture2D(quad);
1120         break;
1121     case Extensions3DChromium::GL_TEXTURE_EXTERNAL_OES:
1122         drawStreamTexture(quad);
1123         break;
1124     default:
1125         CRASH(); // Someone updated convertVFCFormatToGC3DFormat above but update this!
1126     }
1127 }
1128
1129 struct TextureProgramBinding {
1130     template<class Program> void set(Program* program)
1131     {
1132         ASSERT(program && program->initialized());
1133         programId = program->program();
1134         samplerLocation = program->fragmentShader().samplerLocation();
1135         matrixLocation = program->vertexShader().matrixLocation();
1136         alphaLocation = program->fragmentShader().alphaLocation();
1137     }
1138     int programId;
1139     int samplerLocation;
1140     int matrixLocation;
1141     int alphaLocation;
1142 };
1143
1144 struct TexTransformTextureProgramBinding : TextureProgramBinding {
1145     template<class Program> void set(Program* program)
1146     {
1147         TextureProgramBinding::set(program);
1148         texTransformLocation = program->vertexShader().texTransformLocation();
1149     }
1150     int texTransformLocation;
1151 };
1152
1153 void LayerRendererChromium::drawTextureQuad(const CCTextureDrawQuad* quad)
1154 {
1155     ASSERT(CCProxy::isImplThread());
1156
1157     TexTransformTextureProgramBinding binding;
1158     if (quad->flipped())
1159         binding.set(textureProgramFlip());
1160     else
1161         binding.set(textureProgram());
1162     GLC(context(), context()->useProgram(binding.programId));
1163     GLC(context(), context()->uniform1i(binding.samplerLocation, 0));
1164     const FloatRect& uvRect = quad->uvRect();
1165     GLC(context(), context()->uniform4f(binding.texTransformLocation, uvRect.x(), uvRect.y(), uvRect.width(), uvRect.height()));
1166
1167     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
1168     GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, quad->textureId()));
1169
1170     // FIXME: setting the texture parameters every time is redundant. Move this code somewhere
1171     // where it will only happen once per texture.
1172     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
1173     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
1174     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
1175     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
1176
1177     if (!quad->premultipliedAlpha())
1178         GLC(context(), context()->blendFunc(GraphicsContext3D::SRC_ALPHA, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
1179
1180     const IntSize& bounds = quad->quadRect().size();
1181
1182     drawTexturedQuad(quad->layerTransform(), bounds.width(), bounds.height(), quad->opacity(), sharedGeometryQuad(), binding.matrixLocation, binding.alphaLocation, -1);
1183
1184     if (!quad->premultipliedAlpha())
1185         GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
1186 }
1187
1188 void LayerRendererChromium::drawIOSurfaceQuad(const CCIOSurfaceDrawQuad* quad)
1189 {
1190     ASSERT(CCProxy::isImplThread());
1191     TexTransformTextureProgramBinding binding;
1192     binding.set(textureIOSurfaceProgram());
1193
1194     GLC(context(), context()->useProgram(binding.programId));
1195     GLC(context(), context()->uniform1i(binding.samplerLocation, 0));
1196     GLC(context(), context()->uniform4f(binding.texTransformLocation, 0, 0, quad->ioSurfaceSize().width(), quad->ioSurfaceSize().height()));
1197
1198     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
1199     GLC(context(), context()->bindTexture(Extensions3D::TEXTURE_RECTANGLE_ARB, quad->ioSurfaceTextureId()));
1200
1201     // FIXME: setting the texture parameters every time is redundant. Move this code somewhere
1202     // where it will only happen once per texture.
1203     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
1204     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
1205     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
1206     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
1207
1208     const IntSize& bounds = quad->quadRect().size();
1209
1210     drawTexturedQuad(quad->layerTransform(), bounds.width(), bounds.height(), quad->opacity(), sharedGeometryQuad(), binding.matrixLocation, binding.alphaLocation, -1);
1211
1212     GLC(context(), context()->bindTexture(Extensions3D::TEXTURE_RECTANGLE_ARB, 0));
1213 }
1214
1215 void LayerRendererChromium::drawHeadsUpDisplay(ManagedTexture* hudTexture, const IntSize& hudSize)
1216 {
1217     GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
1218     GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
1219     GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
1220     useRenderPass(m_defaultRenderPass);
1221
1222     const HeadsUpDisplayProgram* program = headsUpDisplayProgram();
1223     ASSERT(program && program->initialized());
1224     GLC(m_context, m_context->activeTexture(GraphicsContext3D::TEXTURE0));
1225     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(m_context);
1226     hudTexture->bindTexture(ccContext.get(), m_implTextureAllocator.get());
1227     GLC(m_context, m_context->useProgram(program->program()));
1228     GLC(m_context, m_context->uniform1i(program->fragmentShader().samplerLocation(), 0));
1229
1230     WebTransformationMatrix matrix;
1231     matrix.translate3d(hudSize.width() * 0.5, hudSize.height() * 0.5, 0);
1232     drawTexturedQuad(matrix, hudSize.width(), hudSize.height(),
1233                      1, sharedGeometryQuad(), program->vertexShader().matrixLocation(),
1234                      program->fragmentShader().alphaLocation(),
1235                      -1);
1236 }
1237
1238 void LayerRendererChromium::finishDrawingFrame()
1239 {
1240     GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
1241     GLC(m_context, m_context->disable(GraphicsContext3D::BLEND));
1242
1243     m_implTextureManager->unprotectAllTextures();
1244
1245     size_t contentsMemoryUseBytes = m_contentsTextureAllocator->currentMemoryUseBytes();
1246     size_t reclaimLimit = TextureManager::reclaimLimitBytes(viewportSize());
1247     size_t preferredLimit = reclaimLimit > contentsMemoryUseBytes ? reclaimLimit - contentsMemoryUseBytes : 0;
1248     m_implTextureManager->setPreferredMemoryLimitBytes(preferredLimit);
1249     m_implTextureManager->reduceMemoryToLimit(preferredLimit);
1250     m_implTextureManager->deleteEvictedTextures(m_implTextureAllocator.get());
1251 }
1252
1253 void LayerRendererChromium::toGLMatrix(float* flattened, const WebTransformationMatrix& m)
1254 {
1255     flattened[0] = m.m11();
1256     flattened[1] = m.m12();
1257     flattened[2] = m.m13();
1258     flattened[3] = m.m14();
1259     flattened[4] = m.m21();
1260     flattened[5] = m.m22();
1261     flattened[6] = m.m23();
1262     flattened[7] = m.m24();
1263     flattened[8] = m.m31();
1264     flattened[9] = m.m32();
1265     flattened[10] = m.m33();
1266     flattened[11] = m.m34();
1267     flattened[12] = m.m41();
1268     flattened[13] = m.m42();
1269     flattened[14] = m.m43();
1270     flattened[15] = m.m44();
1271 }
1272
1273 void LayerRendererChromium::drawTexturedQuad(const WebTransformationMatrix& drawMatrix,
1274                                              float width, float height, float opacity, const FloatQuad& quad,
1275                                              int matrixLocation, int alphaLocation, int quadLocation)
1276 {
1277     static float glMatrix[16];
1278
1279     WebTransformationMatrix renderMatrix = drawMatrix;
1280
1281     // Apply a scaling factor to size the quad from 1x1 to its intended size.
1282     renderMatrix.scale3d(width, height, 1);
1283
1284     // Apply the projection matrix before sending the transform over to the shader.
1285     toGLMatrix(&glMatrix[0], m_projectionMatrix * renderMatrix);
1286
1287     GLC(m_context, m_context->uniformMatrix4fv(matrixLocation, 1, false, &glMatrix[0]));
1288
1289     if (quadLocation != -1) {
1290         float point[8];
1291         point[0] = quad.p1().x();
1292         point[1] = quad.p1().y();
1293         point[2] = quad.p2().x();
1294         point[3] = quad.p2().y();
1295         point[4] = quad.p3().x();
1296         point[5] = quad.p3().y();
1297         point[6] = quad.p4().x();
1298         point[7] = quad.p4().y();
1299         GLC(m_context, m_context->uniform2fv(quadLocation, 4, point));
1300     }
1301
1302     if (alphaLocation != -1)
1303         GLC(m_context, m_context->uniform1f(alphaLocation, opacity));
1304
1305     GLC(m_context, m_context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0));
1306 }
1307
1308 void LayerRendererChromium::copyTextureToFramebuffer(int textureId, const IntSize& bounds, const WebTransformationMatrix& drawMatrix)
1309 {
1310     const RenderPassProgram* program = renderPassProgram();
1311
1312     GLC(context(), context()->activeTexture(GraphicsContext3D::TEXTURE0));
1313     GLC(context(), context()->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
1314     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
1315     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
1316     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
1317     GLC(context(), context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
1318
1319     GLC(context(), context()->useProgram(program->program()));
1320     GLC(context(), context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
1321     drawTexturedQuad(drawMatrix, bounds.width(), bounds.height(), 1, sharedGeometryQuad(),
1322                                     program->vertexShader().matrixLocation(),
1323                                     program->fragmentShader().alphaLocation(),
1324                                     -1);
1325 }
1326
1327 void LayerRendererChromium::finish()
1328 {
1329     TRACE_EVENT("LayerRendererChromium::finish", this, 0);
1330     m_context->finish();
1331 }
1332
1333 bool LayerRendererChromium::swapBuffers(const IntRect& subBuffer)
1334 {
1335     // FIXME: Remove this once gpu process supports ignoring swap buffers command while framebuffer is discarded.
1336     //        Alternatively (preferably?), protect all cc code so as not to attempt a swap after a framebuffer discard.
1337     if (m_isFramebufferDiscarded) {
1338         m_client->setFullRootLayerDamage();
1339         return false;
1340     }
1341
1342     TRACE_EVENT("LayerRendererChromium::swapBuffers", this, 0);
1343     // We're done! Time to swapbuffers!
1344
1345     if (m_capabilities.usingPartialSwap) {
1346         // If supported, we can save significant bandwidth by only swapping the damaged/scissored region (clamped to the viewport)
1347         IntRect clippedSubBuffer = subBuffer;
1348         clippedSubBuffer.intersect(IntRect(IntPoint::zero(), viewportSize()));
1349         Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(m_context->getExtensions());
1350         int flippedYPosOfRectBottom = viewportHeight() - clippedSubBuffer.y() - clippedSubBuffer.height();
1351         extensions3DChromium->postSubBufferCHROMIUM(clippedSubBuffer.x(), flippedYPosOfRectBottom, clippedSubBuffer.width(), clippedSubBuffer.height());
1352     } else
1353         // Note that currently this has the same effect as swapBuffers; we should
1354         // consider exposing a different entry point on GraphicsContext3D.
1355         m_context->prepareTexture();
1356
1357     return true;
1358 }
1359
1360 void LayerRendererChromium::onSwapBuffersComplete()
1361 {
1362     m_client->onSwapBuffersComplete();
1363 }
1364
1365 void LayerRendererChromium::discardFramebuffer()
1366 {
1367     if (m_isFramebufferDiscarded)
1368         return;
1369
1370     if (!m_capabilities.usingDiscardFramebuffer)
1371         return;
1372
1373     Extensions3D* extensions = m_context->getExtensions();
1374     Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(extensions);
1375     // FIXME: Update attachments argument to appropriate values once they are no longer ignored.
1376     extensions3DChromium->discardFramebufferEXT(GraphicsContext3D::TEXTURE_2D, 0, 0);
1377     m_isFramebufferDiscarded = true;
1378
1379     // Damage tracker needs a full reset every time framebuffer is discarded.
1380     m_client->setFullRootLayerDamage();
1381 }
1382
1383 void LayerRendererChromium::ensureFramebuffer()
1384 {
1385     if (!m_isFramebufferDiscarded)
1386         return;
1387
1388     if (!m_capabilities.usingDiscardFramebuffer)
1389         return;
1390
1391     Extensions3D* extensions = m_context->getExtensions();
1392     Extensions3DChromium* extensions3DChromium = static_cast<Extensions3DChromium*>(extensions);
1393     extensions3DChromium->ensureFramebufferCHROMIUM();
1394     m_isFramebufferDiscarded = false;
1395 }
1396
1397 void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& rect)
1398 {
1399     ASSERT(rect.maxX() <= viewportWidth() && rect.maxY() <= viewportHeight());
1400
1401     if (!pixels)
1402         return;
1403
1404     makeContextCurrent();
1405
1406     bool doWorkaround = needsLionIOSurfaceReadbackWorkaround();
1407
1408     Platform3DObject temporaryTexture = NullPlatform3DObject;
1409     Platform3DObject temporaryFBO = NullPlatform3DObject;
1410     GraphicsContext3D* context = m_context.get();
1411
1412     if (doWorkaround) {
1413         // On Mac OS X 10.7, calling glReadPixels against an FBO whose color attachment is an
1414         // IOSurface-backed texture causes corruption of future glReadPixels calls, even those on
1415         // different OpenGL contexts. It is believed that this is the root cause of top crasher
1416         // http://crbug.com/99393. <rdar://problem/10949687>
1417
1418         temporaryTexture = context->createTexture();
1419         GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, temporaryTexture));
1420         GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
1421         GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
1422         GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE));
1423         GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE));
1424         // Copy the contents of the current (IOSurface-backed) framebuffer into a temporary texture.
1425         GLC(context, context->copyTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 0, 0, rect.maxX(), rect.maxY(), 0));
1426         temporaryFBO = context->createFramebuffer();
1427         // Attach this texture to an FBO, and perform the readback from that FBO.
1428         GLC(context, context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, temporaryFBO));
1429         GLC(context, context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, temporaryTexture, 0));
1430
1431         ASSERT(context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) == GraphicsContext3D::FRAMEBUFFER_COMPLETE);
1432     }
1433
1434     GLC(context, context->readPixels(rect.x(), rect.y(), rect.width(), rect.height(),
1435                                      GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels));
1436
1437     if (doWorkaround) {
1438         // Clean up.
1439         GLC(context, context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
1440         GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0));
1441         GLC(context, context->deleteFramebuffer(temporaryFBO));
1442         GLC(context, context->deleteTexture(temporaryTexture));
1443     }
1444 }
1445
1446 bool LayerRendererChromium::getFramebufferTexture(ManagedTexture* texture, const IntRect& deviceRect)
1447 {
1448     if (!texture->reserve(deviceRect.size(), GraphicsContext3D::RGB))
1449         return false;
1450
1451     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(m_context);
1452     texture->bindTexture(ccContext.get(), m_implTextureAllocator.get());
1453     GLC(m_context, m_context->copyTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, texture->format(),
1454                                              deviceRect.x(), deviceRect.y(), deviceRect.width(), deviceRect.height(), 0));
1455     return true;
1456 }
1457
1458 bool LayerRendererChromium::isCurrentRenderPass(const CCRenderPass* renderPass)
1459 {
1460     return m_currentRenderPass == renderPass && !m_currentManagedTexture;
1461 }
1462
1463 bool LayerRendererChromium::useRenderPass(const CCRenderPass* renderPass)
1464 {
1465     m_currentRenderPass = renderPass;
1466     m_currentManagedTexture = 0;
1467
1468     if (renderPass == m_defaultRenderPass) {
1469         GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
1470         setDrawFramebufferRect(renderPass->framebufferOutputRect(), true);
1471         return true;
1472     }
1473
1474     if (!renderPass->targetSurface()->prepareContentsTexture(this))
1475         return false;
1476
1477     return bindFramebufferToTexture(renderPass->targetSurface()->contentsTexture(), renderPass->framebufferOutputRect());
1478 }
1479
1480 bool LayerRendererChromium::useManagedTexture(ManagedTexture* texture, const IntRect& viewportRect)
1481 {
1482     m_currentRenderPass = 0;
1483     m_currentManagedTexture = texture;
1484
1485     return bindFramebufferToTexture(texture, viewportRect);
1486 }
1487
1488 bool LayerRendererChromium::bindFramebufferToTexture(ManagedTexture* texture, const IntRect& framebufferRect)
1489 {
1490     GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId));
1491
1492     RefPtr<CCGraphicsContext> ccContext = CCGraphicsContext::create3D(m_context);
1493     texture->framebufferTexture2D(ccContext.get(), m_implTextureAllocator.get());
1494
1495 #if !defined ( NDEBUG )
1496     if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
1497         ASSERT_NOT_REACHED();
1498         return false;
1499     }
1500 #endif
1501
1502     setDrawFramebufferRect(framebufferRect, false);
1503
1504     return true;
1505 }
1506
1507 // Sets the scissor region to the given rectangle. The coordinate system for the
1508 // scissorRect has its origin at the top left corner of the current visible rect.
1509 void LayerRendererChromium::setScissorToRect(const IntRect& scissorRect)
1510 {
1511     IntRect framebufferOutputRect = (m_currentRenderPass ? m_currentRenderPass->framebufferOutputRect() : m_defaultRenderPass->framebufferOutputRect());
1512
1513     GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST));
1514
1515     // The scissor coordinates must be supplied in viewport space so we need to offset
1516     // by the relative position of the top left corner of the current render pass.
1517     int scissorX = scissorRect.x() - framebufferOutputRect.x();
1518     // When rendering to the default render surface we're rendering upside down so the top
1519     // of the GL scissor is the bottom of our layer.
1520     // But, if rendering to offscreen texture, we reverse our sense of 'upside down'.
1521     int scissorY;
1522     if (isCurrentRenderPass(m_defaultRenderPass))
1523         scissorY = framebufferOutputRect.height() - (scissorRect.maxY() - framebufferOutputRect.y());
1524     else
1525         scissorY = scissorRect.y() - framebufferOutputRect.y();
1526     GLC(m_context, m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height()));
1527 }
1528
1529 bool LayerRendererChromium::makeContextCurrent()
1530 {
1531     return m_context->makeContextCurrent();
1532 }
1533
1534 // Sets the coordinate range of content that ends being drawn onto the target render surface.
1535 // The target render surface is assumed to have an origin at 0, 0 and the width and height of
1536 // of the drawRect.
1537 void LayerRendererChromium::setDrawFramebufferRect(const IntRect& drawRect, bool flipY)
1538 {
1539     if (flipY)
1540         m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.maxY(), drawRect.y());
1541     else
1542         m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.maxX(), drawRect.y(), drawRect.maxY());
1543     GLC(m_context, m_context->viewport(0, 0, drawRect.width(), drawRect.height()));
1544     m_windowMatrix = screenMatrix(0, 0, drawRect.width(), drawRect.height());
1545 }
1546
1547
1548 bool LayerRendererChromium::initializeSharedObjects()
1549 {
1550     TRACE_EVENT("LayerRendererChromium::initializeSharedObjects", this, 0);
1551     makeContextCurrent();
1552
1553     // Create an FBO for doing offscreen rendering.
1554     GLC(m_context, m_offscreenFramebufferId = m_context->createFramebuffer());
1555
1556     // We will always need these programs to render, so create the programs eagerly so that the shader compilation can
1557     // start while we do other work. Other programs are created lazily on first access.
1558     m_sharedGeometry = adoptPtr(new GeometryBinding(m_context.get()));
1559     m_renderPassProgram = adoptPtr(new RenderPassProgram(m_context.get()));
1560     m_tileProgram = adoptPtr(new TileProgram(m_context.get()));
1561     m_tileProgramOpaque = adoptPtr(new TileProgramOpaque(m_context.get()));
1562
1563     GLC(m_context, m_context->flush());
1564
1565     m_implTextureManager = TextureManager::create(TextureManager::highLimitBytes(viewportSize()),
1566                                                   TextureManager::reclaimLimitBytes(viewportSize()),
1567                                                   m_capabilities.maxTextureSize);
1568     m_textureCopier = AcceleratedTextureCopier::create(m_context.get());
1569     if (m_textureUploaderSetting == ThrottledUploader)
1570         m_textureUploader = ThrottledTextureUploader::create(m_context.get());
1571     else
1572         m_textureUploader = UnthrottledTextureUploader::create();
1573     m_contentsTextureAllocator = TrackingTextureAllocator::create(m_context.get());
1574     m_implTextureAllocator = TrackingTextureAllocator::create(m_context.get());
1575     if (m_capabilities.usingTextureUsageHint)
1576         m_implTextureAllocator->setTextureUsageHint(TrackingTextureAllocator::FramebufferAttachment);
1577     if (m_capabilities.usingTextureStorageExtension) {
1578         m_contentsTextureAllocator->setUseTextureStorageExt(true);
1579         m_implTextureAllocator->setUseTextureStorageExt(true);
1580     }
1581
1582     return true;
1583 }
1584
1585 const LayerRendererChromium::TileCheckerboardProgram* LayerRendererChromium::tileCheckerboardProgram()
1586 {
1587     if (!m_tileCheckerboardProgram)
1588         m_tileCheckerboardProgram = adoptPtr(new TileCheckerboardProgram(m_context.get()));
1589     if (!m_tileCheckerboardProgram->initialized()) {
1590         TRACE_EVENT("LayerRendererChromium::checkerboardProgram::initalize", this, 0);
1591         m_tileCheckerboardProgram->initialize(m_context.get());
1592     }
1593     return m_tileCheckerboardProgram.get();
1594 }
1595
1596 const LayerRendererChromium::SolidColorProgram* LayerRendererChromium::solidColorProgram()
1597 {
1598     if (!m_solidColorProgram)
1599         m_solidColorProgram = adoptPtr(new SolidColorProgram(m_context.get()));
1600     if (!m_solidColorProgram->initialized()) {
1601         TRACE_EVENT("LayerRendererChromium::solidColorProgram::initialize", this, 0);
1602         m_solidColorProgram->initialize(m_context.get());
1603     }
1604     return m_solidColorProgram.get();
1605 }
1606
1607 const LayerRendererChromium::HeadsUpDisplayProgram* LayerRendererChromium::headsUpDisplayProgram()
1608 {
1609     if (!m_headsUpDisplayProgram)
1610         m_headsUpDisplayProgram = adoptPtr(new HeadsUpDisplayProgram(m_context.get()));
1611     if (!m_headsUpDisplayProgram->initialized()) {
1612         TRACE_EVENT("LayerRendererChromium::headsUpDisplayProgram::initialize", this, 0);
1613         m_headsUpDisplayProgram->initialize(m_context.get());
1614     }
1615     return m_headsUpDisplayProgram.get();
1616 }
1617
1618 const LayerRendererChromium::RenderPassProgram* LayerRendererChromium::renderPassProgram()
1619 {
1620     ASSERT(m_renderPassProgram);
1621     if (!m_renderPassProgram->initialized()) {
1622         TRACE_EVENT("LayerRendererChromium::renderPassProgram::initialize", this, 0);
1623         m_renderPassProgram->initialize(m_context.get());
1624     }
1625     return m_renderPassProgram.get();
1626 }
1627
1628 const LayerRendererChromium::RenderPassProgramAA* LayerRendererChromium::renderPassProgramAA()
1629 {
1630     if (!m_renderPassProgramAA)
1631         m_renderPassProgramAA = adoptPtr(new RenderPassProgramAA(m_context.get()));
1632     if (!m_renderPassProgramAA->initialized()) {
1633         TRACE_EVENT("LayerRendererChromium::renderPassProgramAA::initialize", this, 0);
1634         m_renderPassProgramAA->initialize(m_context.get());
1635     }
1636     return m_renderPassProgramAA.get();
1637 }
1638
1639 const LayerRendererChromium::RenderPassMaskProgram* LayerRendererChromium::renderPassMaskProgram()
1640 {
1641     if (!m_renderPassMaskProgram)
1642         m_renderPassMaskProgram = adoptPtr(new RenderPassMaskProgram(m_context.get()));
1643     if (!m_renderPassMaskProgram->initialized()) {
1644         TRACE_EVENT("LayerRendererChromium::renderPassMaskProgram::initialize", this, 0);
1645         m_renderPassMaskProgram->initialize(m_context.get());
1646     }
1647     return m_renderPassMaskProgram.get();
1648 }
1649
1650 const LayerRendererChromium::RenderPassMaskProgramAA* LayerRendererChromium::renderPassMaskProgramAA()
1651 {
1652     if (!m_renderPassMaskProgramAA)
1653         m_renderPassMaskProgramAA = adoptPtr(new RenderPassMaskProgramAA(m_context.get()));
1654     if (!m_renderPassMaskProgramAA->initialized()) {
1655         TRACE_EVENT("LayerRendererChromium::renderPassMaskProgramAA::initialize", this, 0);
1656         m_renderPassMaskProgramAA->initialize(m_context.get());
1657     }
1658     return m_renderPassMaskProgramAA.get();
1659 }
1660
1661 const LayerRendererChromium::TileProgram* LayerRendererChromium::tileProgram()
1662 {
1663     ASSERT(m_tileProgram);
1664     if (!m_tileProgram->initialized()) {
1665         TRACE_EVENT("LayerRendererChromium::tileProgram::initialize", this, 0);
1666         m_tileProgram->initialize(m_context.get());
1667     }
1668     return m_tileProgram.get();
1669 }
1670
1671 const LayerRendererChromium::TileProgramOpaque* LayerRendererChromium::tileProgramOpaque()
1672 {
1673     ASSERT(m_tileProgramOpaque);
1674     if (!m_tileProgramOpaque->initialized()) {
1675         TRACE_EVENT("LayerRendererChromium::tileProgramOpaque::initialize", this, 0);
1676         m_tileProgramOpaque->initialize(m_context.get());
1677     }
1678     return m_tileProgramOpaque.get();
1679 }
1680
1681 const LayerRendererChromium::TileProgramAA* LayerRendererChromium::tileProgramAA()
1682 {
1683     if (!m_tileProgramAA)
1684         m_tileProgramAA = adoptPtr(new TileProgramAA(m_context.get()));
1685     if (!m_tileProgramAA->initialized()) {
1686         TRACE_EVENT("LayerRendererChromium::tileProgramAA::initialize", this, 0);
1687         m_tileProgramAA->initialize(m_context.get());
1688     }
1689     return m_tileProgramAA.get();
1690 }
1691
1692 const LayerRendererChromium::TileProgramSwizzle* LayerRendererChromium::tileProgramSwizzle()
1693 {
1694     if (!m_tileProgramSwizzle)
1695         m_tileProgramSwizzle = adoptPtr(new TileProgramSwizzle(m_context.get()));
1696     if (!m_tileProgramSwizzle->initialized()) {
1697         TRACE_EVENT("LayerRendererChromium::tileProgramSwizzle::initialize", this, 0);
1698         m_tileProgramSwizzle->initialize(m_context.get());
1699     }
1700     return m_tileProgramSwizzle.get();
1701 }
1702
1703 const LayerRendererChromium::TileProgramSwizzleOpaque* LayerRendererChromium::tileProgramSwizzleOpaque()
1704 {
1705     if (!m_tileProgramSwizzleOpaque)
1706         m_tileProgramSwizzleOpaque = adoptPtr(new TileProgramSwizzleOpaque(m_context.get()));
1707     if (!m_tileProgramSwizzleOpaque->initialized()) {
1708         TRACE_EVENT("LayerRendererChromium::tileProgramSwizzleOpaque::initialize", this, 0);
1709         m_tileProgramSwizzleOpaque->initialize(m_context.get());
1710     }
1711     return m_tileProgramSwizzleOpaque.get();
1712 }
1713
1714 const LayerRendererChromium::TileProgramSwizzleAA* LayerRendererChromium::tileProgramSwizzleAA()
1715 {
1716     if (!m_tileProgramSwizzleAA)
1717         m_tileProgramSwizzleAA = adoptPtr(new TileProgramSwizzleAA(m_context.get()));
1718     if (!m_tileProgramSwizzleAA->initialized()) {
1719         TRACE_EVENT("LayerRendererChromium::tileProgramSwizzleAA::initialize", this, 0);
1720         m_tileProgramSwizzleAA->initialize(m_context.get());
1721     }
1722     return m_tileProgramSwizzleAA.get();
1723 }
1724
1725 const LayerRendererChromium::TextureProgram* LayerRendererChromium::textureProgram()
1726 {
1727     if (!m_textureProgram)
1728         m_textureProgram = adoptPtr(new TextureProgram(m_context.get()));
1729     if (!m_textureProgram->initialized()) {
1730         TRACE_EVENT("LayerRendererChromium::textureProgram::initialize", this, 0);
1731         m_textureProgram->initialize(m_context.get());
1732     }
1733     return m_textureProgram.get();
1734 }
1735
1736 const LayerRendererChromium::TextureProgramFlip* LayerRendererChromium::textureProgramFlip()
1737 {
1738     if (!m_textureProgramFlip)
1739         m_textureProgramFlip = adoptPtr(new TextureProgramFlip(m_context.get()));
1740     if (!m_textureProgramFlip->initialized()) {
1741         TRACE_EVENT("LayerRendererChromium::textureProgramFlip::initialize", this, 0);
1742         m_textureProgramFlip->initialize(m_context.get());
1743     }
1744     return m_textureProgramFlip.get();
1745 }
1746
1747 const LayerRendererChromium::TextureIOSurfaceProgram* LayerRendererChromium::textureIOSurfaceProgram()
1748 {
1749     if (!m_textureIOSurfaceProgram)
1750         m_textureIOSurfaceProgram = adoptPtr(new TextureIOSurfaceProgram(m_context.get()));
1751     if (!m_textureIOSurfaceProgram->initialized()) {
1752         TRACE_EVENT("LayerRendererChromium::textureIOSurfaceProgram::initialize", this, 0);
1753         m_textureIOSurfaceProgram->initialize(m_context.get());
1754     }
1755     return m_textureIOSurfaceProgram.get();
1756 }
1757
1758 const LayerRendererChromium::VideoYUVProgram* LayerRendererChromium::videoYUVProgram()
1759 {
1760     if (!m_videoYUVProgram)
1761         m_videoYUVProgram = adoptPtr(new VideoYUVProgram(m_context.get()));
1762     if (!m_videoYUVProgram->initialized()) {
1763         TRACE_EVENT("LayerRendererChromium::videoYUVProgram::initialize", this, 0);
1764         m_videoYUVProgram->initialize(m_context.get());
1765     }
1766     return m_videoYUVProgram.get();
1767 }
1768
1769 const LayerRendererChromium::VideoStreamTextureProgram* LayerRendererChromium::videoStreamTextureProgram()
1770 {
1771     if (!m_videoStreamTextureProgram)
1772         m_videoStreamTextureProgram = adoptPtr(new VideoStreamTextureProgram(m_context.get()));
1773     if (!m_videoStreamTextureProgram->initialized()) {
1774         TRACE_EVENT("LayerRendererChromium::streamTextureProgram::initialize", this, 0);
1775         m_videoStreamTextureProgram->initialize(m_context.get());
1776     }
1777     return m_videoStreamTextureProgram.get();
1778 }
1779
1780 void LayerRendererChromium::cleanupSharedObjects()
1781 {
1782     makeContextCurrent();
1783
1784     m_sharedGeometry.clear();
1785
1786     if (m_tileProgram)
1787         m_tileProgram->cleanup(m_context.get());
1788     if (m_tileProgramOpaque)
1789         m_tileProgramOpaque->cleanup(m_context.get());
1790     if (m_tileProgramSwizzle)
1791         m_tileProgramSwizzle->cleanup(m_context.get());
1792     if (m_tileProgramSwizzleOpaque)
1793         m_tileProgramSwizzleOpaque->cleanup(m_context.get());
1794     if (m_tileProgramAA)
1795         m_tileProgramAA->cleanup(m_context.get());
1796     if (m_tileProgramSwizzleAA)
1797         m_tileProgramSwizzleAA->cleanup(m_context.get());
1798     if (m_tileCheckerboardProgram)
1799         m_tileCheckerboardProgram->cleanup(m_context.get());
1800
1801     if (m_renderPassMaskProgram)
1802         m_renderPassMaskProgram->cleanup(m_context.get());
1803     if (m_renderPassProgram)
1804         m_renderPassProgram->cleanup(m_context.get());
1805     if (m_renderPassMaskProgramAA)
1806         m_renderPassMaskProgramAA->cleanup(m_context.get());
1807     if (m_renderPassProgramAA)
1808         m_renderPassProgramAA->cleanup(m_context.get());
1809
1810     if (m_textureProgram)
1811         m_textureProgram->cleanup(m_context.get());
1812     if (m_textureProgramFlip)
1813         m_textureProgramFlip->cleanup(m_context.get());
1814     if (m_textureIOSurfaceProgram)
1815         m_textureIOSurfaceProgram->cleanup(m_context.get());
1816
1817     if (m_videoYUVProgram)
1818         m_videoYUVProgram->cleanup(m_context.get());
1819     if (m_videoStreamTextureProgram)
1820         m_videoStreamTextureProgram->cleanup(m_context.get());
1821
1822     if (m_solidColorProgram)
1823         m_solidColorProgram->cleanup(m_context.get());
1824
1825     if (m_headsUpDisplayProgram)
1826         m_headsUpDisplayProgram->cleanup(m_context.get());
1827
1828     if (m_offscreenFramebufferId)
1829         GLC(m_context, m_context->deleteFramebuffer(m_offscreenFramebufferId));
1830
1831     m_textureCopier.clear();
1832     m_textureUploader.clear();
1833
1834     releaseRenderPassTextures();
1835 }
1836
1837 bool LayerRendererChromium::isContextLost()
1838 {
1839     return (m_context.get()->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR);
1840 }
1841
1842 } // namespace WebCore
1843
1844 #endif // USE(ACCELERATED_COMPOSITING)