1 // Copyright 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/gl_renderer.h"
7 #include "base/debug/trace_event.h"
8 #include "base/logging.h"
9 #include "base/string_split.h"
10 #include "base/string_util.h"
11 #include "build/build_config.h"
12 #include "cc/damage_tracker.h"
13 #include "cc/geometry_binding.h"
14 #include "cc/layer_quad.h"
15 #include "cc/math_util.h"
16 #include "cc/platform_color.h"
17 #include "cc/priority_calculator.h"
19 #include "cc/render_pass.h"
20 #include "cc/render_surface_filters.h"
21 #include "cc/scoped_resource.h"
22 #include "cc/single_thread_proxy.h"
23 #include "cc/stream_video_draw_quad.h"
24 #include "cc/texture_draw_quad.h"
25 #include "cc/video_layer_impl.h"
26 #include "third_party/khronos/GLES2/gl2.h"
27 #include "third_party/khronos/GLES2/gl2ext.h"
28 #include "third_party/skia/include/core/SkBitmap.h"
29 #include "third_party/skia/include/core/SkColor.h"
30 #include "third_party/skia/include/gpu/GrContext.h"
31 #include "third_party/skia/include/gpu/GrTexture.h"
32 #include "third_party/skia/include/gpu/SkGpuDevice.h"
33 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h"
34 #include "ui/gfx/quad_f.h"
35 #include "ui/gfx/rect_conversions.h"
36 #include <public/WebGraphicsContext3D.h>
37 #include <public/WebSharedGraphicsContext3D.h>
43 using WebKit::WebGraphicsContext3D
;
44 using WebKit::WebGraphicsMemoryAllocation
;
45 using WebKit::WebSharedGraphicsContext3D
;
51 bool needsIOSurfaceReadbackWorkaround()
53 #if defined(OS_MACOSX)
60 } // anonymous namespace
62 scoped_ptr
<GLRenderer
> GLRenderer::create(RendererClient
* client
, ResourceProvider
* resourceProvider
)
64 scoped_ptr
<GLRenderer
> renderer(make_scoped_ptr(new GLRenderer(client
, resourceProvider
)));
65 if (!renderer
->initialize())
66 return scoped_ptr
<GLRenderer
>();
68 return renderer
.Pass();
71 GLRenderer::GLRenderer(RendererClient
* client
, ResourceProvider
* resourceProvider
)
72 : DirectRenderer(client
, resourceProvider
)
73 , m_offscreenFramebufferId(0)
74 , m_sharedGeometryQuad(gfx::RectF(-0.5f
, -0.5f
, 1.0f
, 1.0f
))
75 , m_context(resourceProvider
->graphicsContext3D())
76 , m_isViewportChanged(false)
77 , m_isFramebufferDiscarded(false)
78 , m_discardFramebufferWhenNotVisible(false)
79 , m_isUsingBindUniform(false)
81 , m_isScissorEnabled(false)
86 bool GLRenderer::initialize()
88 if (!m_context
->makeContextCurrent())
91 m_context
->setContextLostCallback(this);
92 m_context
->pushGroupMarkerEXT("CompositorContext");
94 std::string extensionsString
= UTF16ToASCII(m_context
->getString(GL_EXTENSIONS
));
95 std::vector
<std::string
> extensionsList
;
96 base::SplitString(extensionsString
, ' ', &extensionsList
);
97 std::set
<string
> extensions(extensionsList
.begin(), extensionsList
.end());
99 if (settings().acceleratePainting
&& extensions
.count("GL_EXT_texture_format_BGRA8888")
100 && extensions
.count("GL_EXT_read_format_bgra"))
101 m_capabilities
.usingAcceleratedPainting
= true;
103 m_capabilities
.usingAcceleratedPainting
= false;
106 m_capabilities
.contextHasCachedFrontBuffer
= extensions
.count("GL_CHROMIUM_front_buffer_cached");
108 m_capabilities
.usingPartialSwap
= settings().partialSwapEnabled
&& extensions
.count("GL_CHROMIUM_post_sub_buffer");
110 // Use the swapBuffers callback only with the threaded proxy.
111 if (m_client
->hasImplThread())
112 m_capabilities
.usingSwapCompleteCallback
= extensions
.count("GL_CHROMIUM_swapbuffers_complete_callback");
113 if (m_capabilities
.usingSwapCompleteCallback
)
114 m_context
->setSwapBuffersCompleteCallbackCHROMIUM(this);
116 m_capabilities
.usingSetVisibility
= extensions
.count("GL_CHROMIUM_set_visibility");
118 if (extensions
.count("GL_CHROMIUM_iosurface"))
119 DCHECK(extensions
.count("GL_ARB_texture_rectangle"));
121 m_capabilities
.usingGpuMemoryManager
= extensions
.count("GL_CHROMIUM_gpu_memory_manager");
122 if (m_capabilities
.usingGpuMemoryManager
)
123 m_context
->setMemoryAllocationChangedCallbackCHROMIUM(this);
125 m_capabilities
.usingDiscardFramebuffer
= extensions
.count("GL_CHROMIUM_discard_framebuffer");
127 m_capabilities
.usingEglImage
= extensions
.count("GL_OES_EGL_image_external");
129 GLC(m_context
, m_context
->getIntegerv(GL_MAX_TEXTURE_SIZE
, &m_capabilities
.maxTextureSize
));
130 m_capabilities
.bestTextureFormat
= PlatformColor::bestTextureFormat(m_context
, extensions
.count("GL_EXT_texture_format_BGRA8888"));
132 m_isUsingBindUniform
= extensions
.count("GL_CHROMIUM_bind_uniform_location");
134 // Make sure scissoring starts as disabled.
135 GLC(m_context
, m_context
->disable(GL_SCISSOR_TEST
));
136 DCHECK(!m_isScissorEnabled
);
138 if (!initializeSharedObjects())
141 // Make sure the viewport and context gets initialized, even if it is to zero.
146 GLRenderer::~GLRenderer()
148 m_context
->setSwapBuffersCompleteCallbackCHROMIUM(0);
149 m_context
->setMemoryAllocationChangedCallbackCHROMIUM(0);
150 m_context
->setContextLostCallback(0);
151 cleanupSharedObjects();
154 const RendererCapabilities
& GLRenderer::capabilities() const
156 return m_capabilities
;
159 WebGraphicsContext3D
* GLRenderer::context()
164 void GLRenderer::debugGLCall(WebGraphicsContext3D
* context
, const char* command
, const char* file
, int line
)
166 unsigned long error
= context
->getError();
167 if (error
!= GL_NO_ERROR
)
168 LOG(ERROR
) << "GL command failed: File: " << file
<< "\n\tLine " << line
<< "\n\tcommand: " << command
<< ", error " << static_cast<int>(error
) << "\n";
171 void GLRenderer::setVisible(bool visible
)
173 if (m_visible
== visible
)
177 enforceMemoryPolicy();
179 // TODO: Replace setVisibilityCHROMIUM with an extension to explicitly manage front/backbuffers
181 if (m_capabilities
.usingSetVisibility
)
182 m_context
->setVisibilityCHROMIUM(visible
);
185 void GLRenderer::sendManagedMemoryStats(size_t bytesVisible
, size_t bytesVisibleAndNearby
, size_t bytesAllocated
)
187 WebKit::WebGraphicsManagedMemoryStats stats
;
188 stats
.bytesVisible
= bytesVisible
;
189 stats
.bytesVisibleAndNearby
= bytesVisibleAndNearby
;
190 stats
.bytesAllocated
= bytesAllocated
;
191 stats
.backbufferRequested
= !m_isFramebufferDiscarded
;
192 m_context
->sendManagedMemoryStatsCHROMIUM(&stats
);
195 void GLRenderer::releaseRenderPassTextures()
197 m_renderPassTextures
.clear();
200 void GLRenderer::viewportChanged()
202 m_isViewportChanged
= true;
205 void GLRenderer::clearFramebuffer(DrawingFrame
& frame
)
207 // On DEBUG builds, opaque render passes are cleared to blue to easily see regions that were not drawn on the screen.
208 if (frame
.currentRenderPass
->has_transparent_background
)
209 GLC(m_context
, m_context
->clearColor(0, 0, 0, 0));
211 GLC(m_context
, m_context
->clearColor(0, 0, 1, 1));
214 if (frame
.currentRenderPass
->has_transparent_background
)
216 m_context
->clear(GL_COLOR_BUFFER_BIT
);
219 void GLRenderer::beginDrawingFrame(DrawingFrame
& frame
)
221 // FIXME: Remove this once framebuffer is automatically recreated on first use
224 if (viewportSize().IsEmpty())
227 TRACE_EVENT0("cc", "GLRenderer::drawLayers");
228 if (m_isViewportChanged
) {
229 // Only reshape when we know we are going to draw. Otherwise, the reshape
230 // can leave the window at the wrong size if we never draw and the proper
231 // viewport size is never set.
232 m_isViewportChanged
= false;
233 m_context
->reshape(viewportWidth(), viewportHeight());
236 makeContextCurrent();
237 // Bind the common vertex attributes used for drawing all the layers.
238 m_sharedGeometry
->prepareForDraw();
240 GLC(m_context
, m_context
->disable(GL_DEPTH_TEST
));
241 GLC(m_context
, m_context
->disable(GL_CULL_FACE
));
242 GLC(m_context
, m_context
->colorMask(true, true, true, true));
243 GLC(m_context
, m_context
->enable(GL_BLEND
));
244 m_blendShadow
= true;
245 GLC(m_context
, m_context
->blendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
));
246 GLC(context(), context()->activeTexture(GL_TEXTURE0
));
250 void GLRenderer::doNoOp()
252 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, 0));
253 GLC(m_context
, m_context
->flush());
256 void GLRenderer::drawQuad(DrawingFrame
& frame
, const DrawQuad
* quad
)
258 DCHECK(quad
->rect
.Contains(quad
->visible_rect
));
259 if (quad
->material
!= DrawQuad::TEXTURE_CONTENT
) {
260 flushTextureQuadCache();
261 setBlendEnabled(quad
->ShouldDrawWithBlending());
264 switch (quad
->material
) {
265 case DrawQuad::INVALID
:
268 case DrawQuad::CHECKERBOARD
:
269 drawCheckerboardQuad(frame
, CheckerboardDrawQuad::MaterialCast(quad
));
271 case DrawQuad::DEBUG_BORDER
:
272 drawDebugBorderQuad(frame
, DebugBorderDrawQuad::MaterialCast(quad
));
274 case DrawQuad::IO_SURFACE_CONTENT
:
275 drawIOSurfaceQuad(frame
, IOSurfaceDrawQuad::MaterialCast(quad
));
277 case DrawQuad::RENDER_PASS
:
278 drawRenderPassQuad(frame
, RenderPassDrawQuad::MaterialCast(quad
));
280 case DrawQuad::SOLID_COLOR
:
281 drawSolidColorQuad(frame
, SolidColorDrawQuad::MaterialCast(quad
));
283 case DrawQuad::STREAM_VIDEO_CONTENT
:
284 drawStreamVideoQuad(frame
, StreamVideoDrawQuad::MaterialCast(quad
));
286 case DrawQuad::TEXTURE_CONTENT
:
287 enqueueTextureQuad(frame
, TextureDrawQuad::MaterialCast(quad
));
289 case DrawQuad::TILED_CONTENT
:
290 drawTileQuad(frame
, TileDrawQuad::MaterialCast(quad
));
292 case DrawQuad::YUV_VIDEO_CONTENT
:
293 drawYUVVideoQuad(frame
, YUVVideoDrawQuad::MaterialCast(quad
));
298 void GLRenderer::drawCheckerboardQuad(const DrawingFrame
& frame
, const CheckerboardDrawQuad
* quad
)
300 const TileCheckerboardProgram
* program
= tileCheckerboardProgram();
301 DCHECK(program
&& (program
->initialized() || isContextLost()));
302 setUseProgram(program
->program());
304 SkColor color
= quad
->color
;
305 GLC(context(), context()->uniform4f(program
->fragmentShader().colorLocation(), SkColorGetR(color
) / 255.0, SkColorGetG(color
) / 255.0, SkColorGetB(color
) / 255.0, 1));
307 const int checkerboardWidth
= 16;
308 float frequency
= 1.0 / checkerboardWidth
;
310 gfx::Rect tileRect
= quad
->rect
;
311 float texOffsetX
= tileRect
.x() % checkerboardWidth
;
312 float texOffsetY
= tileRect
.y() % checkerboardWidth
;
313 float texScaleX
= tileRect
.width();
314 float texScaleY
= tileRect
.height();
315 GLC(context(), context()->uniform4f(program
->fragmentShader().texTransformLocation(), texOffsetX
, texOffsetY
, texScaleX
, texScaleY
));
317 GLC(context(), context()->uniform1f(program
->fragmentShader().frequencyLocation(), frequency
));
319 setShaderOpacity(quad
->opacity(), program
->fragmentShader().alphaLocation());
320 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
323 void GLRenderer::drawDebugBorderQuad(const DrawingFrame
& frame
, const DebugBorderDrawQuad
* quad
)
325 static float glMatrix
[16];
326 const SolidColorProgram
* program
= solidColorProgram();
327 DCHECK(program
&& (program
->initialized() || isContextLost()));
328 setUseProgram(program
->program());
330 // Use the full quadRect for debug quads to not move the edges based on partial swaps.
331 const gfx::Rect
& layerRect
= quad
->rect
;
332 gfx::Transform renderMatrix
= quad
->quadTransform();
333 renderMatrix
.Translate(0.5 * layerRect
.width() + layerRect
.x(), 0.5 * layerRect
.height() + layerRect
.y());
334 renderMatrix
.Scale(layerRect
.width(), layerRect
.height());
335 GLRenderer::toGLMatrix(&glMatrix
[0], frame
.projectionMatrix
* renderMatrix
);
336 GLC(context(), context()->uniformMatrix4fv(program
->vertexShader().matrixLocation(), 1, false, &glMatrix
[0]));
338 SkColor color
= quad
->color
;
339 float alpha
= SkColorGetA(color
) / 255.0;
341 GLC(context(), context()->uniform4f(program
->fragmentShader().colorLocation(), (SkColorGetR(color
) / 255.0) * alpha
, (SkColorGetG(color
) / 255.0) * alpha
, (SkColorGetB(color
) / 255.0) * alpha
, alpha
));
343 GLC(context(), context()->lineWidth(quad
->width
));
345 // The indices for the line are stored in the same array as the triangle indices.
346 GLC(context(), context()->drawElements(GL_LINE_LOOP
, 4, GL_UNSIGNED_SHORT
, 0));
349 static WebGraphicsContext3D
* getFilterContext(bool hasImplThread
)
352 return WebSharedGraphicsContext3D::compositorThreadContext();
354 return WebSharedGraphicsContext3D::mainThreadContext();
357 static GrContext
* getFilterGrContext(bool hasImplThread
)
360 return WebSharedGraphicsContext3D::compositorThreadGrContext();
362 return WebSharedGraphicsContext3D::mainThreadGrContext();
365 static inline SkBitmap
applyFilters(GLRenderer
* renderer
, const WebKit::WebFilterOperations
& filters
, ScopedResource
* sourceTexture
, bool hasImplThread
)
367 if (filters
.isEmpty())
370 WebGraphicsContext3D
* filterContext
= getFilterContext(hasImplThread
);
371 GrContext
* filterGrContext
= getFilterGrContext(hasImplThread
);
373 if (!filterContext
|| !filterGrContext
)
376 renderer
->context()->flush();
378 ResourceProvider::ScopedWriteLockGL
lock(renderer
->resourceProvider(), sourceTexture
->id());
379 SkBitmap source
= RenderSurfaceFilters::apply(filters
, lock
.textureId(), sourceTexture
->size(), filterContext
, filterGrContext
);
383 static SkBitmap
applyImageFilter(GLRenderer
* renderer
, SkImageFilter
* filter
, ScopedResource
* sourceTexture
, bool hasImplThread
)
388 WebGraphicsContext3D
* context3d
= getFilterContext(hasImplThread
);
389 GrContext
* grContext
= getFilterGrContext(hasImplThread
);
391 if (!context3d
|| !grContext
)
394 renderer
->context()->flush();
396 ResourceProvider::ScopedWriteLockGL
lock(renderer
->resourceProvider(), sourceTexture
->id());
398 // Wrap the source texture in a Ganesh platform texture.
399 GrPlatformTextureDesc platformTextureDescription
;
400 platformTextureDescription
.fWidth
= sourceTexture
->size().width();
401 platformTextureDescription
.fHeight
= sourceTexture
->size().height();
402 platformTextureDescription
.fConfig
= kSkia8888_GrPixelConfig
;
403 platformTextureDescription
.fTextureHandle
= lock
.textureId();
404 skia::RefPtr
<GrTexture
> texture
= skia::AdoptRef(grContext
->createPlatformTexture(platformTextureDescription
));
406 // Place the platform texture inside an SkBitmap.
408 source
.setConfig(SkBitmap::kARGB_8888_Config
, sourceTexture
->size().width(), sourceTexture
->size().height());
409 skia::RefPtr
<SkGrPixelRef
> pixelRef
= skia::AdoptRef(new SkGrPixelRef(texture
.get()));
410 source
.setPixelRef(pixelRef
.get());
412 // Create a scratch texture for backing store.
414 desc
.fFlags
= kRenderTarget_GrTextureFlagBit
| kNoStencil_GrTextureFlagBit
;
416 desc
.fWidth
= source
.width();
417 desc
.fHeight
= source
.height();
418 desc
.fConfig
= kSkia8888_GrPixelConfig
;
419 GrAutoScratchTexture
scratchTexture(grContext
, desc
, GrContext::kExact_ScratchTexMatch
);
420 skia::RefPtr
<GrTexture
> backingStore
= skia::AdoptRef(scratchTexture
.detach());
422 // Create a device and canvas using that backing store.
423 SkGpuDevice
device(grContext
, backingStore
.get());
424 SkCanvas
canvas(&device
);
426 // Draw the source bitmap through the filter to the canvas.
428 paint
.setImageFilter(filter
);
430 canvas
.drawSprite(source
, 0, 0, &paint
);
433 return device
.accessBitmap(false);
436 scoped_ptr
<ScopedResource
> GLRenderer::drawBackgroundFilters(
437 DrawingFrame
& frame
, const RenderPassDrawQuad
* quad
,
438 const WebKit::WebFilterOperations
& filters
,
439 const gfx::Transform
& contentsDeviceTransform
,
440 const gfx::Transform
& contentsDeviceTransformInverse
)
442 // This method draws a background filter, which applies a filter to any pixels behind the quad and seen through its background.
443 // The algorithm works as follows:
444 // 1. Compute a bounding box around the pixels that will be visible through the quad.
445 // 2. Read the pixels in the bounding box into a buffer R.
446 // 3. Apply the background filter to R, so that it is applied in the pixels' coordinate space.
447 // 4. Apply the quad's inverse transform to map the pixels in R into the quad's content space. This implicitly
448 // clips R by the content bounds of the quad since the destination texture has bounds matching the quad's content.
449 // 5. Draw the background texture for the contents using the same transform as used to draw the contents itself. This is done
450 // without blending to replace the current background pixels with the new filtered background.
451 // 6. Draw the contents of the quad over drop of the new background with blending, as per usual. The filtered background
452 // pixels will show through any non-opaque pixels in this draws.
454 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
456 // FIXME: When this algorithm changes, update LayerTreeHost::prioritizeTextures() accordingly.
458 if (filters
.isEmpty())
459 return scoped_ptr
<ScopedResource
>();
461 // FIXME: We only allow background filters on an opaque render surface because other surfaces may contain
462 // translucent pixels, and the contents behind those translucent pixels wouldn't have the filter applied.
463 if (frame
.currentRenderPass
->has_transparent_background
)
464 return scoped_ptr
<ScopedResource
>();
465 DCHECK(!frame
.currentTexture
);
467 // FIXME: Do a single readback for both the surface and replica and cache the filtered results (once filter textures are not reused).
468 gfx::Rect deviceRect
= gfx::ToEnclosingRect(MathUtil::mapClippedRect(contentsDeviceTransform
, sharedGeometryQuad().BoundingBox()));
470 int top
, right
, bottom
, left
;
471 filters
.getOutsets(top
, right
, bottom
, left
);
472 deviceRect
.Inset(-left
, -top
, -right
, -bottom
);
474 deviceRect
.Intersect(frame
.currentRenderPass
->output_rect
);
476 scoped_ptr
<ScopedResource
> deviceBackgroundTexture
= ScopedResource::create(m_resourceProvider
);
477 if (!getFramebufferTexture(deviceBackgroundTexture
.get(), deviceRect
))
478 return scoped_ptr
<ScopedResource
>();
480 SkBitmap filteredDeviceBackground
= applyFilters(this, filters
, deviceBackgroundTexture
.get(), m_client
->hasImplThread());
481 if (!filteredDeviceBackground
.getTexture())
482 return scoped_ptr
<ScopedResource
>();
484 GrTexture
* texture
= reinterpret_cast<GrTexture
*>(filteredDeviceBackground
.getTexture());
485 int filteredDeviceBackgroundTextureId
= texture
->getTextureHandle();
487 scoped_ptr
<ScopedResource
> backgroundTexture
= ScopedResource::create(m_resourceProvider
);
488 if (!backgroundTexture
->Allocate(Renderer::ImplPool
, quad
->rect
.size(), GL_RGBA
, ResourceProvider::TextureUsageFramebuffer
))
489 return scoped_ptr
<ScopedResource
>();
491 const RenderPass
* targetRenderPass
= frame
.currentRenderPass
;
492 bool usingBackgroundTexture
= useScopedTexture(frame
, backgroundTexture
.get(), quad
->rect
);
494 if (usingBackgroundTexture
) {
495 // Copy the readback pixels from device to the background texture for the surface.
496 gfx::Transform deviceToFramebufferTransform
;
497 deviceToFramebufferTransform
.Translate(quad
->rect
.width() / 2.0, quad
->rect
.height() / 2.0);
498 deviceToFramebufferTransform
.Scale3d(quad
->rect
.width(), quad
->rect
.height(), 1);
499 deviceToFramebufferTransform
.PreconcatTransform(contentsDeviceTransformInverse
);
500 copyTextureToFramebuffer(frame
, filteredDeviceBackgroundTextureId
, deviceRect
, deviceToFramebufferTransform
);
503 useRenderPass(frame
, targetRenderPass
);
505 if (!usingBackgroundTexture
)
506 return scoped_ptr
<ScopedResource
>();
507 return backgroundTexture
.Pass();
510 void GLRenderer::drawRenderPassQuad(DrawingFrame
& frame
, const RenderPassDrawQuad
* quad
)
512 CachedResource
* contentsTexture
= m_renderPassTextures
.get(quad
->render_pass_id
);
513 if (!contentsTexture
|| !contentsTexture
->id())
516 const RenderPass
* renderPass
= frame
.renderPassesById
->get(quad
->render_pass_id
);
521 gfx::Transform quadRectMatrix
;
522 quadRectTransform(&quadRectMatrix
, quad
->quadTransform(), quad
->rect
);
523 gfx::Transform contentsDeviceTransform
= MathUtil::to2dTransform(frame
.windowMatrix
* frame
.projectionMatrix
* quadRectMatrix
);
525 // Can only draw surface if device matrix is invertible.
526 if (!contentsDeviceTransform
.IsInvertible())
529 gfx::Transform contentsDeviceTransformInverse
= MathUtil::inverse(contentsDeviceTransform
);
530 scoped_ptr
<ScopedResource
> backgroundTexture
= drawBackgroundFilters(
531 frame
, quad
, renderPass
->background_filters
,
532 contentsDeviceTransform
, contentsDeviceTransformInverse
);
534 // FIXME: Cache this value so that we don't have to do it for both the surface and its replica.
535 // Apply filters to the contents texture.
536 SkBitmap filterBitmap
;
537 if (renderPass
->filter
) {
538 filterBitmap
= applyImageFilter(this, renderPass
->filter
.get(), contentsTexture
, m_client
->hasImplThread());
540 filterBitmap
= applyFilters(this, renderPass
->filters
, contentsTexture
, m_client
->hasImplThread());
543 // Draw the background texture if there is one.
544 if (backgroundTexture
) {
545 DCHECK(backgroundTexture
->size() == quad
->rect
.size());
546 ResourceProvider::ScopedReadLockGL
lock(m_resourceProvider
, backgroundTexture
->id());
547 copyTextureToFramebuffer(frame
, lock
.textureId(), quad
->rect
, quad
->quadTransform());
550 bool clipped
= false;
551 gfx::QuadF deviceQuad
= MathUtil::mapQuad(contentsDeviceTransform
, sharedGeometryQuad(), clipped
);
553 LayerQuad deviceLayerBounds
= LayerQuad(gfx::QuadF(deviceQuad
.BoundingBox()));
554 LayerQuad deviceLayerEdges
= LayerQuad(deviceQuad
);
556 // Use anti-aliasing programs only when necessary.
557 bool useAA
= (!deviceQuad
.IsRectilinear() || !deviceQuad
.BoundingBox().IsExpressibleAsRect());
559 deviceLayerBounds
.inflateAntiAliasingDistance();
560 deviceLayerEdges
.inflateAntiAliasingDistance();
563 scoped_ptr
<ResourceProvider::ScopedReadLockGL
> maskResourceLock
;
564 unsigned maskTextureId
= 0;
565 if (quad
->mask_resource_id
) {
566 maskResourceLock
.reset(new ResourceProvider::ScopedReadLockGL(m_resourceProvider
, quad
->mask_resource_id
));
567 maskTextureId
= maskResourceLock
->textureId();
570 // FIXME: use the backgroundTexture and blend the background in with this draw instead of having a separate copy of the background texture.
572 scoped_ptr
<ResourceProvider::ScopedReadLockGL
> contentsResourceLock
;
573 if (filterBitmap
.getTexture()) {
574 GrTexture
* texture
= reinterpret_cast<GrTexture
*>(filterBitmap
.getTexture());
575 context()->bindTexture(GL_TEXTURE_2D
, texture
->getTextureHandle());
577 contentsResourceLock
= make_scoped_ptr(new ResourceProvider::ScopedSamplerGL(m_resourceProvider
, contentsTexture
->id(),
578 GL_TEXTURE_2D
, GL_LINEAR
));
580 int shaderQuadLocation
= -1;
581 int shaderEdgeLocation
= -1;
582 int shaderMaskSamplerLocation
= -1;
583 int shaderMaskTexCoordScaleLocation
= -1;
584 int shaderMaskTexCoordOffsetLocation
= -1;
585 int shaderMatrixLocation
= -1;
586 int shaderAlphaLocation
= -1;
587 if (useAA
&& maskTextureId
) {
588 const RenderPassMaskProgramAA
* program
= renderPassMaskProgramAA();
589 setUseProgram(program
->program());
590 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
592 shaderQuadLocation
= program
->vertexShader().pointLocation();
593 shaderEdgeLocation
= program
->fragmentShader().edgeLocation();
594 shaderMaskSamplerLocation
= program
->fragmentShader().maskSamplerLocation();
595 shaderMaskTexCoordScaleLocation
= program
->fragmentShader().maskTexCoordScaleLocation();
596 shaderMaskTexCoordOffsetLocation
= program
->fragmentShader().maskTexCoordOffsetLocation();
597 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
598 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
599 } else if (!useAA
&& maskTextureId
) {
600 const RenderPassMaskProgram
* program
= renderPassMaskProgram();
601 setUseProgram(program
->program());
602 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
604 shaderMaskSamplerLocation
= program
->fragmentShader().maskSamplerLocation();
605 shaderMaskTexCoordScaleLocation
= program
->fragmentShader().maskTexCoordScaleLocation();
606 shaderMaskTexCoordOffsetLocation
= program
->fragmentShader().maskTexCoordOffsetLocation();
607 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
608 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
609 } else if (useAA
&& !maskTextureId
) {
610 const RenderPassProgramAA
* program
= renderPassProgramAA();
611 setUseProgram(program
->program());
612 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
614 shaderQuadLocation
= program
->vertexShader().pointLocation();
615 shaderEdgeLocation
= program
->fragmentShader().edgeLocation();
616 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
617 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
619 const RenderPassProgram
* program
= renderPassProgram();
620 setUseProgram(program
->program());
621 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
623 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
624 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
627 if (shaderMaskSamplerLocation
!= -1) {
628 DCHECK(shaderMaskTexCoordScaleLocation
!= 1);
629 DCHECK(shaderMaskTexCoordOffsetLocation
!= 1);
630 GLC(context(), context()->activeTexture(GL_TEXTURE1
));
631 GLC(context(), context()->uniform1i(shaderMaskSamplerLocation
, 1));
632 GLC(context(), context()->uniform2f(shaderMaskTexCoordScaleLocation
, quad
->mask_tex_coord_scale_x
, quad
->mask_tex_coord_scale_y
));
633 GLC(context(), context()->uniform2f(shaderMaskTexCoordOffsetLocation
, quad
->mask_tex_coord_offset_x
, quad
->mask_tex_coord_offset_y
));
634 m_resourceProvider
->bindForSampling(quad
->mask_resource_id
, GL_TEXTURE_2D
, GL_LINEAR
);
635 GLC(context(), context()->activeTexture(GL_TEXTURE0
));
638 if (shaderEdgeLocation
!= -1) {
640 deviceLayerEdges
.toFloatArray(edge
);
641 deviceLayerBounds
.toFloatArray(&edge
[12]);
642 GLC(context(), context()->uniform3fv(shaderEdgeLocation
, 8, edge
));
645 // Map device space quad to surface space. contentsDeviceTransform has no 3d component since it was generated with to2dTransform() so we don't need to project.
646 gfx::QuadF surfaceQuad
= MathUtil::mapQuad(contentsDeviceTransformInverse
, deviceLayerEdges
.ToQuadF(), clipped
);
649 setShaderOpacity(quad
->opacity(), shaderAlphaLocation
);
650 setShaderQuadF(surfaceQuad
, shaderQuadLocation
);
651 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, shaderMatrixLocation
);
653 // Flush the compositor context before the filter bitmap goes out of
654 // scope, so the draw gets processed before the filter texture gets deleted.
655 if (filterBitmap
.getTexture())
659 void GLRenderer::drawSolidColorQuad(const DrawingFrame
& frame
, const SolidColorDrawQuad
* quad
)
661 const SolidColorProgram
* program
= solidColorProgram();
662 setUseProgram(program
->program());
664 SkColor color
= quad
->color
;
665 float opacity
= quad
->opacity();
666 float alpha
= (SkColorGetA(color
) / 255.0) * opacity
;
668 GLC(context(), context()->uniform4f(program
->fragmentShader().colorLocation(), (SkColorGetR(color
) / 255.0) * alpha
, (SkColorGetG(color
) / 255.0) * alpha
, (SkColorGetB(color
) / 255.0) * alpha
, alpha
));
670 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
673 struct TileProgramUniforms
{
675 unsigned samplerLocation
;
676 unsigned vertexTexTransformLocation
;
677 unsigned fragmentTexTransformLocation
;
678 unsigned edgeLocation
;
679 unsigned matrixLocation
;
680 unsigned alphaLocation
;
681 unsigned pointLocation
;
685 static void tileUniformLocation(T program
, TileProgramUniforms
& uniforms
)
687 uniforms
.program
= program
->program();
688 uniforms
.vertexTexTransformLocation
= program
->vertexShader().vertexTexTransformLocation();
689 uniforms
.matrixLocation
= program
->vertexShader().matrixLocation();
690 uniforms
.pointLocation
= program
->vertexShader().pointLocation();
692 uniforms
.samplerLocation
= program
->fragmentShader().samplerLocation();
693 uniforms
.alphaLocation
= program
->fragmentShader().alphaLocation();
694 uniforms
.fragmentTexTransformLocation
= program
->fragmentShader().fragmentTexTransformLocation();
695 uniforms
.edgeLocation
= program
->fragmentShader().edgeLocation();
698 void GLRenderer::drawTileQuad(const DrawingFrame
& frame
, const TileDrawQuad
* quad
)
700 gfx::Rect tileRect
= quad
->visible_rect
;
702 gfx::RectF texCoordRect
= quad
->tex_coord_rect
;
703 float texToGeomScaleX
= quad
->rect
.width() / texCoordRect
.width();
704 float texToGeomScaleY
= quad
->rect
.height() / texCoordRect
.height();
706 // texCoordRect corresponds to quadRect, but quadVisibleRect may be
707 // smaller than quadRect due to occlusion or clipping. Adjust
708 // texCoordRect to match.
709 gfx::Vector2d topLeftDiff
= tileRect
.origin() - quad
->rect
.origin();
710 gfx::Vector2d bottomRightDiff
=
711 tileRect
.bottom_right() - quad
->rect
.bottom_right();
712 texCoordRect
.Inset(topLeftDiff
.x() / texToGeomScaleX
,
713 topLeftDiff
.y() / texToGeomScaleY
,
714 -bottomRightDiff
.x() / texToGeomScaleX
,
715 -bottomRightDiff
.y() / texToGeomScaleY
);
717 gfx::RectF
clampGeomRect(tileRect
);
718 gfx::RectF
clampTexRect(texCoordRect
);
719 // Clamp texture coordinates to avoid sampling outside the layer
720 // by deflating the tile region half a texel or half a texel
721 // minus epsilon for one pixel layers. The resulting clamp region
722 // is mapped to the unit square by the vertex shader and mapped
723 // back to normalized texture coordinates by the fragment shader
724 // after being clamped to 0-1 range.
725 const float epsilon
= 1 / 1024.0f
;
726 float texClampX
= std::min(0.5f
, 0.5f
* clampTexRect
.width() - epsilon
);
727 float texClampY
= std::min(0.5f
, 0.5f
* clampTexRect
.height() - epsilon
);
728 float geomClampX
= std::min(texClampX
* texToGeomScaleX
,
729 0.5f
* clampGeomRect
.width() - epsilon
);
730 float geomClampY
= std::min(texClampY
* texToGeomScaleY
,
731 0.5f
* clampGeomRect
.height() - epsilon
);
732 clampGeomRect
.Inset(geomClampX
, geomClampY
, geomClampX
, geomClampY
);
733 clampTexRect
.Inset(texClampX
, texClampY
, texClampX
, texClampY
);
735 // Map clamping rectangle to unit square.
736 float vertexTexTranslateX
= -clampGeomRect
.x() / clampGeomRect
.width();
737 float vertexTexTranslateY
= -clampGeomRect
.y() / clampGeomRect
.height();
738 float vertexTexScaleX
= tileRect
.width() / clampGeomRect
.width();
739 float vertexTexScaleY
= tileRect
.height() / clampGeomRect
.height();
741 // Map to normalized texture coordinates.
742 const gfx::Size
& textureSize
= quad
->texture_size
;
743 float fragmentTexTranslateX
= clampTexRect
.x() / textureSize
.width();
744 float fragmentTexTranslateY
= clampTexRect
.y() / textureSize
.height();
745 float fragmentTexScaleX
= clampTexRect
.width() / textureSize
.width();
746 float fragmentTexScaleY
= clampTexRect
.height() / textureSize
.height();
749 gfx::QuadF localQuad
;
750 gfx::Transform deviceTransform
= MathUtil::to2dTransform(frame
.windowMatrix
* frame
.projectionMatrix
* quad
->quadTransform());
751 if (!deviceTransform
.IsInvertible())
754 bool clipped
= false;
755 gfx::QuadF deviceLayerQuad
= MathUtil::mapQuad(deviceTransform
, gfx::QuadF(quad
->visibleContentRect()), clipped
);
758 TileProgramUniforms uniforms
;
759 // For now, we simply skip anti-aliasing with the quad is clipped. This only happens
760 // on perspective transformed layers that go partially behind the camera.
761 if (quad
->IsAntialiased() && !clipped
) {
762 if (quad
->swizzle_contents
)
763 tileUniformLocation(tileProgramSwizzleAA(), uniforms
);
765 tileUniformLocation(tileProgramAA(), uniforms
);
767 if (quad
->ShouldDrawWithBlending()) {
768 if (quad
->swizzle_contents
)
769 tileUniformLocation(tileProgramSwizzle(), uniforms
);
771 tileUniformLocation(tileProgram(), uniforms
);
773 if (quad
->swizzle_contents
)
774 tileUniformLocation(tileProgramSwizzleOpaque(), uniforms
);
776 tileUniformLocation(tileProgramOpaque(), uniforms
);
780 setUseProgram(uniforms
.program
);
781 GLC(context(), context()->uniform1i(uniforms
.samplerLocation
, 0));
782 bool scaled
= (texToGeomScaleX
!= 1 || texToGeomScaleY
!= 1);
783 GLenum filter
= (quad
->IsAntialiased() || scaled
|| !quad
->quadTransform().IsIdentityOrIntegerTranslation()) ? GL_LINEAR
: GL_NEAREST
;
784 ResourceProvider::ScopedSamplerGL
quadResourceLock(m_resourceProvider
, quad
->resource_id
, GL_TEXTURE_2D
, filter
);
786 bool useAA
= !clipped
&& quad
->IsAntialiased();
788 LayerQuad deviceLayerBounds
= LayerQuad(gfx::QuadF(deviceLayerQuad
.BoundingBox()));
789 deviceLayerBounds
.inflateAntiAliasingDistance();
791 LayerQuad deviceLayerEdges
= LayerQuad(deviceLayerQuad
);
792 deviceLayerEdges
.inflateAntiAliasingDistance();
795 deviceLayerEdges
.toFloatArray(edge
);
796 deviceLayerBounds
.toFloatArray(&edge
[12]);
797 GLC(context(), context()->uniform3fv(uniforms
.edgeLocation
, 8, edge
));
799 GLC(context(), context()->uniform4f(uniforms
.vertexTexTransformLocation
, vertexTexTranslateX
, vertexTexTranslateY
, vertexTexScaleX
, vertexTexScaleY
));
800 GLC(context(), context()->uniform4f(uniforms
.fragmentTexTransformLocation
, fragmentTexTranslateX
, fragmentTexTranslateY
, fragmentTexScaleX
, fragmentTexScaleY
));
802 gfx::PointF bottomRight
= tileRect
.bottom_right();
803 gfx::PointF bottomLeft
= tileRect
.bottom_left();
804 gfx::PointF topLeft
= tileRect
.origin();
805 gfx::PointF topRight
= tileRect
.top_right();
807 // Map points to device space.
808 bottomRight
= MathUtil::mapPoint(deviceTransform
, bottomRight
, clipped
);
810 bottomLeft
= MathUtil::mapPoint(deviceTransform
, bottomLeft
, clipped
);
812 topLeft
= MathUtil::mapPoint(deviceTransform
, topLeft
, clipped
);
814 topRight
= MathUtil::mapPoint(deviceTransform
, topRight
, clipped
);
817 LayerQuad::Edge
bottomEdge(bottomRight
, bottomLeft
);
818 LayerQuad::Edge
leftEdge(bottomLeft
, topLeft
);
819 LayerQuad::Edge
topEdge(topLeft
, topRight
);
820 LayerQuad::Edge
rightEdge(topRight
, bottomRight
);
822 // Only apply anti-aliasing to edges not clipped by culling or scissoring.
823 if (quad
->top_edge_aa
&& tileRect
.y() == quad
->rect
.y())
824 topEdge
= deviceLayerEdges
.top();
825 if (quad
->left_edge_aa
&& tileRect
.x() == quad
->rect
.x())
826 leftEdge
= deviceLayerEdges
.left();
827 if (quad
->right_edge_aa
&& tileRect
.right() == quad
->rect
.right())
828 rightEdge
= deviceLayerEdges
.right();
829 if (quad
->bottom_edge_aa
&& tileRect
.bottom() == quad
->rect
.bottom())
830 bottomEdge
= deviceLayerEdges
.bottom();
832 float sign
= gfx::QuadF(tileRect
).IsCounterClockwise() ? -1 : 1;
833 bottomEdge
.scale(sign
);
834 leftEdge
.scale(sign
);
836 rightEdge
.scale(sign
);
838 // Create device space quad.
839 LayerQuad
deviceQuad(leftEdge
, topEdge
, rightEdge
, bottomEdge
);
841 // Map device space quad to local space. deviceTransform has no 3d component since it was generated with to2dTransform() so we don't need to project.
842 gfx::Transform deviceTransformInverse
= MathUtil::inverse(deviceTransform
);
843 localQuad
= MathUtil::mapQuad(deviceTransformInverse
, deviceQuad
.ToQuadF(), clipped
);
845 // We should not DCHECK(!clipped) here, because anti-aliasing inflation may cause deviceQuad to become
846 // clipped. To our knowledge this scenario does not need to be handled differently than the unclipped case.
848 // Move fragment shader transform to vertex shader. We can do this while
849 // still producing correct results as fragmentTexTransformLocation
850 // should always be non-negative when tiles are transformed in a way
851 // that could result in sampling outside the layer.
852 vertexTexScaleX
*= fragmentTexScaleX
;
853 vertexTexScaleY
*= fragmentTexScaleY
;
854 vertexTexTranslateX
*= fragmentTexScaleX
;
855 vertexTexTranslateY
*= fragmentTexScaleY
;
856 vertexTexTranslateX
+= fragmentTexTranslateX
;
857 vertexTexTranslateY
+= fragmentTexTranslateY
;
859 GLC(context(), context()->uniform4f(uniforms
.vertexTexTransformLocation
, vertexTexTranslateX
, vertexTexTranslateY
, vertexTexScaleX
, vertexTexScaleY
));
861 localQuad
= gfx::RectF(tileRect
);
864 // Normalize to tileRect.
865 localQuad
.Scale(1.0f
/ tileRect
.width(), 1.0f
/ tileRect
.height());
867 setShaderOpacity(quad
->opacity(), uniforms
.alphaLocation
);
868 setShaderQuadF(localQuad
, uniforms
.pointLocation
);
870 // The tile quad shader behaves differently compared to all other shaders.
871 // The transform and vertex data are used to figure out the extents that the
872 // un-antialiased quad should have and which vertex this is and the float
873 // quad passed in via uniform is the actual geometry that gets used to draw
874 // it. This is why this centered rect is used and not the original quadRect.
875 gfx::RectF
centeredRect(gfx::PointF(-0.5 * tileRect
.width(), -0.5 * tileRect
.height()), tileRect
.size());
876 drawQuadGeometry(frame
, quad
->quadTransform(), centeredRect
, uniforms
.matrixLocation
);
879 void GLRenderer::drawYUVVideoQuad(const DrawingFrame
& frame
, const YUVVideoDrawQuad
* quad
)
881 const VideoYUVProgram
* program
= videoYUVProgram();
882 DCHECK(program
&& (program
->initialized() || isContextLost()));
884 const VideoLayerImpl::FramePlane
& yPlane
= quad
->y_plane
;
885 const VideoLayerImpl::FramePlane
& uPlane
= quad
->u_plane
;
886 const VideoLayerImpl::FramePlane
& vPlane
= quad
->v_plane
;
888 GLC(context(), context()->activeTexture(GL_TEXTURE1
));
889 ResourceProvider::ScopedSamplerGL
yPlaneLock(m_resourceProvider
, yPlane
.resourceId
, GL_TEXTURE_2D
, GL_LINEAR
);
890 GLC(context(), context()->activeTexture(GL_TEXTURE2
));
891 ResourceProvider::ScopedSamplerGL
uPlaneLock(m_resourceProvider
, uPlane
.resourceId
, GL_TEXTURE_2D
, GL_LINEAR
);
892 GLC(context(), context()->activeTexture(GL_TEXTURE3
));
893 ResourceProvider::ScopedSamplerGL
vPlaneLock(m_resourceProvider
, vPlane
.resourceId
, GL_TEXTURE_2D
, GL_LINEAR
);
895 setUseProgram(program
->program());
897 GLC(context(), context()->uniform2f(program
->vertexShader().texScaleLocation(), quad
->tex_scale
.width(), quad
->tex_scale
.height()));
898 GLC(context(), context()->uniform1i(program
->fragmentShader().yTextureLocation(), 1));
899 GLC(context(), context()->uniform1i(program
->fragmentShader().uTextureLocation(), 2));
900 GLC(context(), context()->uniform1i(program
->fragmentShader().vTextureLocation(), 3));
902 // These values are magic numbers that are used in the transformation from YUV to RGB color values.
903 // They are taken from the following webpage: http://www.fourcc.org/fccyvrgb.php
905 1.164f
, 1.164f
, 1.164f
,
909 GLC(context(), context()->uniformMatrix3fv(program
->fragmentShader().yuvMatrixLocation(), 1, 0, yuv2RGB
));
911 // These values map to 16, 128, and 128 respectively, and are computed
912 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
913 // They are used in the YUV to RGBA conversion formula:
914 // Y - 16 : Gives 16 values of head and footroom for overshooting
915 // U - 128 : Turns unsigned U into signed U [-128,127]
916 // V - 128 : Turns unsigned V into signed V [-128,127]
917 float yuvAdjust
[3] = {
922 GLC(context(), context()->uniform3fv(program
->fragmentShader().yuvAdjLocation(), 1, yuvAdjust
));
924 setShaderOpacity(quad
->opacity(), program
->fragmentShader().alphaLocation());
925 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
927 // Reset active texture back to texture 0.
928 GLC(context(), context()->activeTexture(GL_TEXTURE0
));
931 void GLRenderer::drawStreamVideoQuad(const DrawingFrame
& frame
, const StreamVideoDrawQuad
* quad
)
933 static float glMatrix
[16];
935 DCHECK(m_capabilities
.usingEglImage
);
937 const VideoStreamTextureProgram
* program
= videoStreamTextureProgram();
938 setUseProgram(program
->program());
940 toGLMatrix(&glMatrix
[0], quad
->matrix
);
941 GLC(context(), context()->uniformMatrix4fv(program
->vertexShader().texMatrixLocation(), 1, false, glMatrix
));
943 GLC(context(), context()->bindTexture(GL_TEXTURE_EXTERNAL_OES
, quad
->texture_id
));
945 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
947 setShaderOpacity(quad
->opacity(), program
->fragmentShader().alphaLocation());
948 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
951 struct TextureProgramBinding
{
952 template<class Program
> void set(
953 Program
* program
, WebKit::WebGraphicsContext3D
* context
)
955 DCHECK(program
&& (program
->initialized() || context
->isContextLost()));
956 programId
= program
->program();
957 samplerLocation
= program
->fragmentShader().samplerLocation();
958 matrixLocation
= program
->vertexShader().matrixLocation();
959 alphaLocation
= program
->fragmentShader().alphaLocation();
967 struct TexTransformTextureProgramBinding
: TextureProgramBinding
{
968 template<class Program
> void set(
969 Program
* program
, WebKit::WebGraphicsContext3D
* context
)
971 TextureProgramBinding::set(program
, context
);
972 texTransformLocation
= program
->vertexShader().texTransformLocation();
974 int texTransformLocation
;
977 void GLRenderer::flushTextureQuadCache()
979 // Check to see if we have anything to draw.
980 if (m_drawCache
.program_id
== 0)
983 // Set the correct blending mode.
984 setBlendEnabled(m_drawCache
.needs_blending
);
986 // Bind the program to the GL state.
987 setUseProgram(m_drawCache
.program_id
);
989 // Assume the current active textures is 0.
990 ResourceProvider::ScopedReadLockGL
lockedQuad(m_resourceProvider
, m_drawCache
.resource_id
);
991 GLC(context(), context()->bindTexture(GL_TEXTURE_2D
, lockedQuad
.textureId()));
993 // set up premultiplied alpha.
994 if (!m_drawCache
.use_premultiplied_alpha
) {
995 // As it turns out, the premultiplied alpha blending function (ONE, ONE_MINUS_SRC_ALPHA)
996 // will never cause the alpha channel to be set to anything less than 1.0 if it is
997 // initialized to that value! Therefore, premultipliedAlpha being false is the first
998 // situation we can generally see an alpha channel less than 1.0 coming out of the
999 // compositor. This is causing platform differences in some layout tests (see
1000 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use a separate
1001 // blend function for the alpha channel to avoid modifying it. Don't use colorMask for this
1002 // as it has performance implications on some platforms.
1003 GLC(context(), context()->blendFuncSeparate(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, GL_ZERO
, GL_ONE
));
1006 // Set the shader opacity.
1007 setShaderOpacity(m_drawCache
.alpha
, m_drawCache
.alpha_location
);
1009 COMPILE_ASSERT(sizeof(Float4
) == 4 * sizeof(float), struct_is_densely_packed
);
1010 COMPILE_ASSERT(sizeof(Float16
) == 16 * sizeof(float), struct_is_densely_packed
);
1012 // Upload the tranforms for both points and uvs.
1013 GLC(m_context
, m_context
->uniformMatrix4fv((int)m_drawCache
.matrix_location
, (int)m_drawCache
.matrix_data
.size(), false, (float*)&m_drawCache
.matrix_data
.front()));
1014 GLC(m_context
, m_context
->uniform4fv((int)m_drawCache
.uv_xform_location
, (int)m_drawCache
.uv_xform_data
.size(), (float*)&m_drawCache
.uv_xform_data
.front()));
1017 GLC(m_context
, m_context
->drawElements(GL_TRIANGLES
, 6 * m_drawCache
.matrix_data
.size(), GL_UNSIGNED_SHORT
, 0));
1019 // Clean up after ourselves (reset state set above).
1020 if (!m_drawCache
.use_premultiplied_alpha
)
1021 GLC(m_context
, m_context
->blendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
));
1024 m_drawCache
.program_id
= 0;
1025 m_drawCache
.uv_xform_data
.resize(0);
1026 m_drawCache
.matrix_data
.resize(0);
1029 void GLRenderer::enqueueTextureQuad(const DrawingFrame
& frame
, const TextureDrawQuad
* quad
)
1031 // Choose the correcte texture program binding
1032 TexTransformTextureProgramBinding binding
;
1034 binding
.set(textureProgramFlip(), context());
1036 binding
.set(textureProgram(), context());
1038 int resourceID
= quad
->resource_id
;
1040 if (m_drawCache
.program_id
!= binding
.programId
||
1041 m_drawCache
.resource_id
!= resourceID
||
1042 m_drawCache
.alpha
!= quad
->opacity() ||
1043 m_drawCache
.use_premultiplied_alpha
!= quad
->premultiplied_alpha
||
1044 m_drawCache
.needs_blending
!= quad
->ShouldDrawWithBlending() ||
1045 m_drawCache
.matrix_data
.size() >= 8) {
1046 flushTextureQuadCache();
1047 m_drawCache
.program_id
= binding
.programId
;
1048 m_drawCache
.resource_id
= resourceID
;
1049 m_drawCache
.alpha
= quad
->opacity();
1050 m_drawCache
.use_premultiplied_alpha
= quad
->premultiplied_alpha
;
1051 m_drawCache
.needs_blending
= quad
->ShouldDrawWithBlending();
1053 m_drawCache
.alpha_location
= binding
.alphaLocation
;
1054 m_drawCache
.uv_xform_location
= binding
.texTransformLocation
;
1055 m_drawCache
.matrix_location
= binding
.matrixLocation
;
1058 // Generate the uv-transform
1059 const gfx::RectF
& uvRect
= quad
->uv_rect
;
1060 Float4 uv
= {uvRect
.x(), uvRect
.y(), uvRect
.width(), uvRect
.height()};
1061 m_drawCache
.uv_xform_data
.push_back(uv
);
1063 // Generate the transform matrix
1064 gfx::Transform quadRectMatrix
;
1065 quadRectTransform(&quadRectMatrix
, quad
->quadTransform(), quad
->rect
);
1066 quadRectMatrix
= frame
.projectionMatrix
* quadRectMatrix
;
1069 quadRectMatrix
.matrix().asColMajorf(m
.data
);
1070 m_drawCache
.matrix_data
.push_back(m
);
1073 void GLRenderer::drawTextureQuad(const DrawingFrame
& frame
, const TextureDrawQuad
* quad
)
1075 TexTransformTextureProgramBinding binding
;
1077 binding
.set(textureProgramFlip(), context());
1079 binding
.set(textureProgram(), context());
1080 setUseProgram(binding
.programId
);
1081 GLC(context(), context()->uniform1i(binding
.samplerLocation
, 0));
1082 const gfx::RectF
& uvRect
= quad
->uv_rect
;
1083 GLC(context(), context()->uniform4f(binding
.texTransformLocation
, uvRect
.x(), uvRect
.y(), uvRect
.width(), uvRect
.height()));
1085 ResourceProvider::ScopedSamplerGL
quadResourceLock(m_resourceProvider
, quad
->resource_id
, GL_TEXTURE_2D
, GL_LINEAR
);
1087 if (!quad
->premultiplied_alpha
) {
1088 // As it turns out, the premultiplied alpha blending function (ONE, ONE_MINUS_SRC_ALPHA)
1089 // will never cause the alpha channel to be set to anything less than 1.0 if it is
1090 // initialized to that value! Therefore, premultipliedAlpha being false is the first
1091 // situation we can generally see an alpha channel less than 1.0 coming out of the
1092 // compositor. This is causing platform differences in some layout tests (see
1093 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use a separate
1094 // blend function for the alpha channel to avoid modifying it. Don't use colorMask for this
1095 // as it has performance implications on some platforms.
1096 GLC(context(), context()->blendFuncSeparate(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, GL_ZERO
, GL_ONE
));
1099 setShaderOpacity(quad
->opacity(), binding
.alphaLocation
);
1100 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, binding
.matrixLocation
);
1102 if (!quad
->premultiplied_alpha
)
1103 GLC(m_context
, m_context
->blendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
));
1106 void GLRenderer::drawIOSurfaceQuad(const DrawingFrame
& frame
, const IOSurfaceDrawQuad
* quad
)
1108 TexTransformTextureProgramBinding binding
;
1109 binding
.set(textureIOSurfaceProgram(), context());
1111 setUseProgram(binding
.programId
);
1112 GLC(context(), context()->uniform1i(binding
.samplerLocation
, 0));
1113 if (quad
->orientation
== IOSurfaceDrawQuad::FLIPPED
)
1114 GLC(context(), context()->uniform4f(binding
.texTransformLocation
, 0, quad
->io_surface_size
.height(), quad
->io_surface_size
.width(), quad
->io_surface_size
.height() * -1.0));
1116 GLC(context(), context()->uniform4f(binding
.texTransformLocation
, 0, 0, quad
->io_surface_size
.width(), quad
->io_surface_size
.height()));
1118 GLC(context(), context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB
, quad
->io_surface_texture_id
));
1120 setShaderOpacity(quad
->opacity(), binding
.alphaLocation
);
1121 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, binding
.matrixLocation
);
1123 GLC(context(), context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB
, 0));
1126 void GLRenderer::finishDrawingFrame(DrawingFrame
& frame
)
1128 m_currentFramebufferLock
.reset();
1129 m_swapBufferRect
.Union(gfx::ToEnclosingRect(frame
.rootDamageRect
));
1131 GLC(m_context
, m_context
->disable(GL_BLEND
));
1132 m_blendShadow
= false;
1135 void GLRenderer::finishDrawingQuadList()
1137 flushTextureQuadCache();
1140 bool GLRenderer::flippedFramebuffer() const
1145 void GLRenderer::ensureScissorTestEnabled()
1147 if (m_isScissorEnabled
)
1150 flushTextureQuadCache();
1151 GLC(m_context
, m_context
->enable(GL_SCISSOR_TEST
));
1152 m_isScissorEnabled
= true;
1155 void GLRenderer::ensureScissorTestDisabled()
1157 if (!m_isScissorEnabled
)
1160 flushTextureQuadCache();
1161 GLC(m_context
, m_context
->disable(GL_SCISSOR_TEST
));
1162 m_isScissorEnabled
= false;
1165 void GLRenderer::toGLMatrix(float* glMatrix
, const gfx::Transform
& transform
)
1167 transform
.matrix().asColMajorf(glMatrix
);
1170 void GLRenderer::setShaderQuadF(const gfx::QuadF
& quad
, int quadLocation
)
1172 if (quadLocation
== -1)
1176 point
[0] = quad
.p1().x();
1177 point
[1] = quad
.p1().y();
1178 point
[2] = quad
.p2().x();
1179 point
[3] = quad
.p2().y();
1180 point
[4] = quad
.p3().x();
1181 point
[5] = quad
.p3().y();
1182 point
[6] = quad
.p4().x();
1183 point
[7] = quad
.p4().y();
1184 GLC(m_context
, m_context
->uniform2fv(quadLocation
, 4, point
));
1187 void GLRenderer::setShaderOpacity(float opacity
, int alphaLocation
)
1189 if (alphaLocation
!= -1)
1190 GLC(m_context
, m_context
->uniform1f(alphaLocation
, opacity
));
1193 void GLRenderer::setBlendEnabled(bool enabled
)
1195 if (enabled
== m_blendShadow
)
1199 GLC(m_context
, m_context
->enable(GL_BLEND
));
1201 GLC(m_context
, m_context
->disable(GL_BLEND
));
1202 m_blendShadow
= enabled
;
1205 void GLRenderer::setUseProgram(unsigned program
)
1207 if (program
== m_programShadow
)
1209 GLC(m_context
, m_context
->useProgram(program
));
1210 m_programShadow
= program
;
1213 void GLRenderer::drawQuadGeometry(const DrawingFrame
& frame
, const gfx::Transform
& drawTransform
, const gfx::RectF
& quadRect
, int matrixLocation
)
1215 gfx::Transform quadRectMatrix
;
1216 quadRectTransform(&quadRectMatrix
, drawTransform
, quadRect
);
1217 static float glMatrix
[16];
1218 toGLMatrix(&glMatrix
[0], frame
.projectionMatrix
* quadRectMatrix
);
1219 GLC(m_context
, m_context
->uniformMatrix4fv(matrixLocation
, 1, false, &glMatrix
[0]));
1221 GLC(m_context
, m_context
->drawElements(GL_TRIANGLES
, 6, GL_UNSIGNED_SHORT
, 0));
1224 void GLRenderer::copyTextureToFramebuffer(const DrawingFrame
& frame
, int textureId
, const gfx::Rect
& rect
, const gfx::Transform
& drawMatrix
)
1226 const RenderPassProgram
* program
= renderPassProgram();
1228 GLC(context(), context()->bindTexture(GL_TEXTURE_2D
, textureId
));
1230 setUseProgram(program
->program());
1231 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
1232 setShaderOpacity(1, program
->fragmentShader().alphaLocation());
1233 drawQuadGeometry(frame
, drawMatrix
, rect
, program
->vertexShader().matrixLocation());
1236 void GLRenderer::finish()
1238 TRACE_EVENT0("cc", "GLRenderer::finish");
1239 m_context
->finish();
1242 bool GLRenderer::swapBuffers()
1245 DCHECK(!m_isFramebufferDiscarded
);
1247 TRACE_EVENT0("cc", "GLRenderer::swapBuffers");
1248 // We're done! Time to swapbuffers!
1250 if (m_capabilities
.usingPartialSwap
) {
1251 // If supported, we can save significant bandwidth by only swapping the damaged/scissored region (clamped to the viewport)
1252 m_swapBufferRect
.Intersect(gfx::Rect(gfx::Point(), viewportSize()));
1253 int flippedYPosOfRectBottom
= viewportHeight() - m_swapBufferRect
.y() - m_swapBufferRect
.height();
1254 m_context
->postSubBufferCHROMIUM(m_swapBufferRect
.x(), flippedYPosOfRectBottom
, m_swapBufferRect
.width(), m_swapBufferRect
.height());
1256 // Note that currently this has the same effect as swapBuffers; we should
1257 // consider exposing a different entry point on WebGraphicsContext3D.
1258 m_context
->prepareTexture();
1261 m_swapBufferRect
= gfx::Rect();
1266 void GLRenderer::onSwapBuffersComplete()
1268 m_client
->onSwapBuffersComplete();
1271 void GLRenderer::onMemoryAllocationChanged(WebGraphicsMemoryAllocation allocation
)
1273 // Just ignore the memory manager when it says to set the limit to zero
1274 // bytes. This will happen when the memory manager thinks that the renderer
1275 // is not visible (which the renderer knows better).
1276 if (allocation
.bytesLimitWhenVisible
) {
1277 ManagedMemoryPolicy
policy(
1278 allocation
.bytesLimitWhenVisible
,
1279 priorityCutoffValue(allocation
.priorityCutoffWhenVisible
),
1280 allocation
.bytesLimitWhenNotVisible
,
1281 priorityCutoffValue(allocation
.priorityCutoffWhenNotVisible
));
1283 if (allocation
.enforceButDoNotKeepAsPolicy
)
1284 m_client
->enforceManagedMemoryPolicy(policy
);
1286 m_client
->setManagedMemoryPolicy(policy
);
1289 bool oldDiscardFramebufferWhenNotVisible
= m_discardFramebufferWhenNotVisible
;
1290 m_discardFramebufferWhenNotVisible
= !allocation
.suggestHaveBackbuffer
;
1291 enforceMemoryPolicy();
1292 if (allocation
.enforceButDoNotKeepAsPolicy
)
1293 m_discardFramebufferWhenNotVisible
= oldDiscardFramebufferWhenNotVisible
;
1296 int GLRenderer::priorityCutoffValue(WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priorityCutoff
)
1298 switch (priorityCutoff
) {
1299 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing
:
1300 return PriorityCalculator::allowNothingCutoff();
1301 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly
:
1302 return PriorityCalculator::allowVisibleOnlyCutoff();
1303 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleAndNearby
:
1304 return PriorityCalculator::allowVisibleAndNearbyCutoff();
1305 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything
:
1306 return PriorityCalculator::allowEverythingCutoff();
1312 void GLRenderer::enforceMemoryPolicy()
1315 TRACE_EVENT0("cc", "GLRenderer::enforceMemoryPolicy dropping resources");
1316 releaseRenderPassTextures();
1317 if (m_discardFramebufferWhenNotVisible
)
1318 discardFramebuffer();
1319 GLC(m_context
, m_context
->flush());
1323 void GLRenderer::discardFramebuffer()
1325 if (m_isFramebufferDiscarded
)
1328 if (!m_capabilities
.usingDiscardFramebuffer
)
1331 // FIXME: Update attachments argument to appropriate values once they are no longer ignored.
1332 m_context
->discardFramebufferEXT(GL_TEXTURE_2D
, 0, 0);
1333 m_isFramebufferDiscarded
= true;
1335 // Damage tracker needs a full reset every time framebuffer is discarded.
1336 m_client
->setFullRootLayerDamage();
1339 void GLRenderer::ensureFramebuffer()
1341 if (!m_isFramebufferDiscarded
)
1344 if (!m_capabilities
.usingDiscardFramebuffer
)
1347 m_context
->ensureFramebufferCHROMIUM();
1348 m_isFramebufferDiscarded
= false;
1351 void GLRenderer::onContextLost()
1353 m_client
->didLoseContext();
1357 void GLRenderer::getFramebufferPixels(void *pixels
, const gfx::Rect
& rect
)
1359 DCHECK(rect
.right() <= viewportWidth());
1360 DCHECK(rect
.bottom() <= viewportHeight());
1365 makeContextCurrent();
1367 bool doWorkaround
= needsIOSurfaceReadbackWorkaround();
1369 GLuint temporaryTexture
= 0;
1370 GLuint temporaryFBO
= 0;
1373 // On Mac OS X, calling glReadPixels against an FBO whose color attachment is an
1374 // IOSurface-backed texture causes corruption of future glReadPixels calls, even those on
1375 // different OpenGL contexts. It is believed that this is the root cause of top crasher
1376 // http://crbug.com/99393. <rdar://problem/10949687>
1378 temporaryTexture
= m_context
->createTexture();
1379 GLC(m_context
, m_context
->bindTexture(GL_TEXTURE_2D
, temporaryTexture
));
1380 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
));
1381 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
));
1382 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
));
1383 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
));
1384 // Copy the contents of the current (IOSurface-backed) framebuffer into a temporary texture.
1385 GLC(m_context
, m_context
->copyTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, 0, 0, viewportSize().width(), viewportSize().height(), 0));
1386 temporaryFBO
= m_context
->createFramebuffer();
1387 // Attach this texture to an FBO, and perform the readback from that FBO.
1388 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, temporaryFBO
));
1389 GLC(m_context
, m_context
->framebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, temporaryTexture
, 0));
1391 DCHECK(m_context
->checkFramebufferStatus(GL_FRAMEBUFFER
) == GL_FRAMEBUFFER_COMPLETE
);
1394 scoped_array
<uint8_t> srcPixels(new uint8_t[rect
.width() * rect
.height() * 4]);
1395 GLC(m_context
, m_context
->readPixels(rect
.x(), viewportSize().height() - rect
.bottom(), rect
.width(), rect
.height(),
1396 GL_RGBA
, GL_UNSIGNED_BYTE
, srcPixels
.get()));
1398 uint8_t* destPixels
= static_cast<uint8_t*>(pixels
);
1399 size_t rowBytes
= rect
.width() * 4;
1400 int numRows
= rect
.height();
1401 size_t totalBytes
= numRows
* rowBytes
;
1402 for (size_t destY
= 0; destY
< totalBytes
; destY
+= rowBytes
) {
1404 size_t srcY
= totalBytes
- destY
- rowBytes
;
1405 // Swizzle BGRA -> RGBA.
1406 for (size_t x
= 0; x
< rowBytes
; x
+= 4) {
1407 destPixels
[destY
+ (x
+0)] = srcPixels
.get()[srcY
+ (x
+2)];
1408 destPixels
[destY
+ (x
+1)] = srcPixels
.get()[srcY
+ (x
+1)];
1409 destPixels
[destY
+ (x
+2)] = srcPixels
.get()[srcY
+ (x
+0)];
1410 destPixels
[destY
+ (x
+3)] = srcPixels
.get()[srcY
+ (x
+3)];
1416 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, 0));
1417 GLC(m_context
, m_context
->bindTexture(GL_TEXTURE_2D
, 0));
1418 GLC(m_context
, m_context
->deleteFramebuffer(temporaryFBO
));
1419 GLC(m_context
, m_context
->deleteTexture(temporaryTexture
));
1422 enforceMemoryPolicy();
1425 bool GLRenderer::getFramebufferTexture(ScopedResource
* texture
, const gfx::Rect
& deviceRect
)
1427 DCHECK(!texture
->id() || (texture
->size() == deviceRect
.size() && texture
->format() == GL_RGB
));
1429 if (!texture
->id() && !texture
->Allocate(Renderer::ImplPool
, deviceRect
.size(), GL_RGB
, ResourceProvider::TextureUsageAny
))
1432 ResourceProvider::ScopedWriteLockGL
lock(m_resourceProvider
, texture
->id());
1433 GLC(m_context
, m_context
->bindTexture(GL_TEXTURE_2D
, lock
.textureId()));
1434 GLC(m_context
, m_context
->copyTexImage2D(GL_TEXTURE_2D
, 0, texture
->format(),
1435 deviceRect
.x(), deviceRect
.y(), deviceRect
.width(), deviceRect
.height(), 0));
1439 bool GLRenderer::useScopedTexture(DrawingFrame
& frame
, const ScopedResource
* texture
, const gfx::Rect
& viewportRect
)
1441 DCHECK(texture
->id());
1442 frame
.currentRenderPass
= 0;
1443 frame
.currentTexture
= texture
;
1445 return bindFramebufferToTexture(frame
, texture
, viewportRect
);
1448 void GLRenderer::bindFramebufferToOutputSurface(DrawingFrame
& frame
)
1450 m_currentFramebufferLock
.reset();
1451 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, 0));
1454 bool GLRenderer::bindFramebufferToTexture(DrawingFrame
& frame
, const ScopedResource
* texture
, const gfx::Rect
& framebufferRect
)
1456 DCHECK(texture
->id());
1458 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, m_offscreenFramebufferId
));
1459 m_currentFramebufferLock
= make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL(m_resourceProvider
, texture
->id()));
1460 unsigned textureId
= m_currentFramebufferLock
->textureId();
1461 GLC(m_context
, m_context
->framebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, textureId
, 0));
1463 DCHECK(m_context
->checkFramebufferStatus(GL_FRAMEBUFFER
) == GL_FRAMEBUFFER_COMPLETE
);
1465 initializeMatrices(frame
, framebufferRect
, false);
1466 setDrawViewportSize(framebufferRect
.size());
1471 void GLRenderer::setScissorTestRect(const gfx::Rect
& scissorRect
)
1473 ensureScissorTestEnabled();
1475 // Don't unnecessarily ask the context to change the scissor, because it
1476 // may cause undesired GPU pipeline flushes.
1477 if (scissorRect
== m_scissorRect
)
1480 m_scissorRect
= scissorRect
;
1481 flushTextureQuadCache();
1482 GLC(m_context
, m_context
->scissor(scissorRect
.x(), scissorRect
.y(), scissorRect
.width(), scissorRect
.height()));
1485 void GLRenderer::setDrawViewportSize(const gfx::Size
& viewportSize
)
1487 GLC(m_context
, m_context
->viewport(0, 0, viewportSize
.width(), viewportSize
.height()));
1490 bool GLRenderer::makeContextCurrent()
1492 return m_context
->makeContextCurrent();
1495 bool GLRenderer::initializeSharedObjects()
1497 TRACE_EVENT0("cc", "GLRenderer::initializeSharedObjects");
1498 makeContextCurrent();
1500 // Create an FBO for doing offscreen rendering.
1501 GLC(m_context
, m_offscreenFramebufferId
= m_context
->createFramebuffer());
1503 // We will always need these programs to render, so create the programs eagerly so that the shader compilation can
1504 // start while we do other work. Other programs are created lazily on first access.
1505 m_sharedGeometry
= make_scoped_ptr(new GeometryBinding(m_context
, quadVertexRect()));
1506 m_renderPassProgram
= make_scoped_ptr(new RenderPassProgram(m_context
));
1507 m_tileProgram
= make_scoped_ptr(new TileProgram(m_context
));
1508 m_tileProgramOpaque
= make_scoped_ptr(new TileProgramOpaque(m_context
));
1510 GLC(m_context
, m_context
->flush());
1515 const GLRenderer::TileCheckerboardProgram
* GLRenderer::tileCheckerboardProgram()
1517 if (!m_tileCheckerboardProgram
)
1518 m_tileCheckerboardProgram
= make_scoped_ptr(new TileCheckerboardProgram(m_context
));
1519 if (!m_tileCheckerboardProgram
->initialized()) {
1520 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
1521 m_tileCheckerboardProgram
->initialize(m_context
, m_isUsingBindUniform
);
1523 return m_tileCheckerboardProgram
.get();
1526 const GLRenderer::SolidColorProgram
* GLRenderer::solidColorProgram()
1528 if (!m_solidColorProgram
)
1529 m_solidColorProgram
= make_scoped_ptr(new SolidColorProgram(m_context
));
1530 if (!m_solidColorProgram
->initialized()) {
1531 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
1532 m_solidColorProgram
->initialize(m_context
, m_isUsingBindUniform
);
1534 return m_solidColorProgram
.get();
1537 const GLRenderer::RenderPassProgram
* GLRenderer::renderPassProgram()
1539 DCHECK(m_renderPassProgram
);
1540 if (!m_renderPassProgram
->initialized()) {
1541 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
1542 m_renderPassProgram
->initialize(m_context
, m_isUsingBindUniform
);
1544 return m_renderPassProgram
.get();
1547 const GLRenderer::RenderPassProgramAA
* GLRenderer::renderPassProgramAA()
1549 if (!m_renderPassProgramAA
)
1550 m_renderPassProgramAA
= make_scoped_ptr(new RenderPassProgramAA(m_context
));
1551 if (!m_renderPassProgramAA
->initialized()) {
1552 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
1553 m_renderPassProgramAA
->initialize(m_context
, m_isUsingBindUniform
);
1555 return m_renderPassProgramAA
.get();
1558 const GLRenderer::RenderPassMaskProgram
* GLRenderer::renderPassMaskProgram()
1560 if (!m_renderPassMaskProgram
)
1561 m_renderPassMaskProgram
= make_scoped_ptr(new RenderPassMaskProgram(m_context
));
1562 if (!m_renderPassMaskProgram
->initialized()) {
1563 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
1564 m_renderPassMaskProgram
->initialize(m_context
, m_isUsingBindUniform
);
1566 return m_renderPassMaskProgram
.get();
1569 const GLRenderer::RenderPassMaskProgramAA
* GLRenderer::renderPassMaskProgramAA()
1571 if (!m_renderPassMaskProgramAA
)
1572 m_renderPassMaskProgramAA
= make_scoped_ptr(new RenderPassMaskProgramAA(m_context
));
1573 if (!m_renderPassMaskProgramAA
->initialized()) {
1574 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
1575 m_renderPassMaskProgramAA
->initialize(m_context
, m_isUsingBindUniform
);
1577 return m_renderPassMaskProgramAA
.get();
1580 const GLRenderer::TileProgram
* GLRenderer::tileProgram()
1582 DCHECK(m_tileProgram
);
1583 if (!m_tileProgram
->initialized()) {
1584 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
1585 m_tileProgram
->initialize(m_context
, m_isUsingBindUniform
);
1587 return m_tileProgram
.get();
1590 const GLRenderer::TileProgramOpaque
* GLRenderer::tileProgramOpaque()
1592 DCHECK(m_tileProgramOpaque
);
1593 if (!m_tileProgramOpaque
->initialized()) {
1594 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
1595 m_tileProgramOpaque
->initialize(m_context
, m_isUsingBindUniform
);
1597 return m_tileProgramOpaque
.get();
1600 const GLRenderer::TileProgramAA
* GLRenderer::tileProgramAA()
1602 if (!m_tileProgramAA
)
1603 m_tileProgramAA
= make_scoped_ptr(new TileProgramAA(m_context
));
1604 if (!m_tileProgramAA
->initialized()) {
1605 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
1606 m_tileProgramAA
->initialize(m_context
, m_isUsingBindUniform
);
1608 return m_tileProgramAA
.get();
1611 const GLRenderer::TileProgramSwizzle
* GLRenderer::tileProgramSwizzle()
1613 if (!m_tileProgramSwizzle
)
1614 m_tileProgramSwizzle
= make_scoped_ptr(new TileProgramSwizzle(m_context
));
1615 if (!m_tileProgramSwizzle
->initialized()) {
1616 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
1617 m_tileProgramSwizzle
->initialize(m_context
, m_isUsingBindUniform
);
1619 return m_tileProgramSwizzle
.get();
1622 const GLRenderer::TileProgramSwizzleOpaque
* GLRenderer::tileProgramSwizzleOpaque()
1624 if (!m_tileProgramSwizzleOpaque
)
1625 m_tileProgramSwizzleOpaque
= make_scoped_ptr(new TileProgramSwizzleOpaque(m_context
));
1626 if (!m_tileProgramSwizzleOpaque
->initialized()) {
1627 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize");
1628 m_tileProgramSwizzleOpaque
->initialize(m_context
, m_isUsingBindUniform
);
1630 return m_tileProgramSwizzleOpaque
.get();
1633 const GLRenderer::TileProgramSwizzleAA
* GLRenderer::tileProgramSwizzleAA()
1635 if (!m_tileProgramSwizzleAA
)
1636 m_tileProgramSwizzleAA
= make_scoped_ptr(new TileProgramSwizzleAA(m_context
));
1637 if (!m_tileProgramSwizzleAA
->initialized()) {
1638 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
1639 m_tileProgramSwizzleAA
->initialize(m_context
, m_isUsingBindUniform
);
1641 return m_tileProgramSwizzleAA
.get();
1644 const GLRenderer::TextureProgram
* GLRenderer::textureProgram()
1646 if (!m_textureProgram
)
1647 m_textureProgram
= make_scoped_ptr(new TextureProgram(m_context
));
1648 if (!m_textureProgram
->initialized()) {
1649 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
1650 m_textureProgram
->initialize(m_context
, m_isUsingBindUniform
);
1651 GLC(context(), context()->uniform1i(m_textureProgram
.get()->fragmentShader().samplerLocation(), 0));
1653 return m_textureProgram
.get();
1656 const GLRenderer::TextureProgramFlip
* GLRenderer::textureProgramFlip()
1658 if (!m_textureProgramFlip
)
1659 m_textureProgramFlip
= make_scoped_ptr(new TextureProgramFlip(m_context
));
1660 if (!m_textureProgramFlip
->initialized()) {
1661 TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize");
1662 m_textureProgramFlip
->initialize(m_context
, m_isUsingBindUniform
);
1663 GLC(context(), context()->uniform1i(m_textureProgramFlip
.get()->fragmentShader().samplerLocation(), 0));
1665 return m_textureProgramFlip
.get();
1668 const GLRenderer::TextureIOSurfaceProgram
* GLRenderer::textureIOSurfaceProgram()
1670 if (!m_textureIOSurfaceProgram
)
1671 m_textureIOSurfaceProgram
= make_scoped_ptr(new TextureIOSurfaceProgram(m_context
));
1672 if (!m_textureIOSurfaceProgram
->initialized()) {
1673 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
1674 m_textureIOSurfaceProgram
->initialize(m_context
, m_isUsingBindUniform
);
1676 return m_textureIOSurfaceProgram
.get();
1679 const GLRenderer::VideoYUVProgram
* GLRenderer::videoYUVProgram()
1681 if (!m_videoYUVProgram
)
1682 m_videoYUVProgram
= make_scoped_ptr(new VideoYUVProgram(m_context
));
1683 if (!m_videoYUVProgram
->initialized()) {
1684 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
1685 m_videoYUVProgram
->initialize(m_context
, m_isUsingBindUniform
);
1687 return m_videoYUVProgram
.get();
1690 const GLRenderer::VideoStreamTextureProgram
* GLRenderer::videoStreamTextureProgram()
1692 if (!m_videoStreamTextureProgram
)
1693 m_videoStreamTextureProgram
= make_scoped_ptr(new VideoStreamTextureProgram(m_context
));
1694 if (!m_videoStreamTextureProgram
->initialized()) {
1695 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
1696 m_videoStreamTextureProgram
->initialize(m_context
, m_isUsingBindUniform
);
1698 return m_videoStreamTextureProgram
.get();
1701 void GLRenderer::cleanupSharedObjects()
1703 makeContextCurrent();
1705 m_sharedGeometry
.reset();
1708 m_tileProgram
->cleanup(m_context
);
1709 if (m_tileProgramOpaque
)
1710 m_tileProgramOpaque
->cleanup(m_context
);
1711 if (m_tileProgramSwizzle
)
1712 m_tileProgramSwizzle
->cleanup(m_context
);
1713 if (m_tileProgramSwizzleOpaque
)
1714 m_tileProgramSwizzleOpaque
->cleanup(m_context
);
1715 if (m_tileProgramAA
)
1716 m_tileProgramAA
->cleanup(m_context
);
1717 if (m_tileProgramSwizzleAA
)
1718 m_tileProgramSwizzleAA
->cleanup(m_context
);
1719 if (m_tileCheckerboardProgram
)
1720 m_tileCheckerboardProgram
->cleanup(m_context
);
1722 if (m_renderPassMaskProgram
)
1723 m_renderPassMaskProgram
->cleanup(m_context
);
1724 if (m_renderPassProgram
)
1725 m_renderPassProgram
->cleanup(m_context
);
1726 if (m_renderPassMaskProgramAA
)
1727 m_renderPassMaskProgramAA
->cleanup(m_context
);
1728 if (m_renderPassProgramAA
)
1729 m_renderPassProgramAA
->cleanup(m_context
);
1731 if (m_textureProgram
)
1732 m_textureProgram
->cleanup(m_context
);
1733 if (m_textureProgramFlip
)
1734 m_textureProgramFlip
->cleanup(m_context
);
1735 if (m_textureIOSurfaceProgram
)
1736 m_textureIOSurfaceProgram
->cleanup(m_context
);
1738 if (m_videoYUVProgram
)
1739 m_videoYUVProgram
->cleanup(m_context
);
1740 if (m_videoStreamTextureProgram
)
1741 m_videoStreamTextureProgram
->cleanup(m_context
);
1743 if (m_solidColorProgram
)
1744 m_solidColorProgram
->cleanup(m_context
);
1746 if (m_offscreenFramebufferId
)
1747 GLC(m_context
, m_context
->deleteFramebuffer(m_offscreenFramebufferId
));
1749 releaseRenderPassTextures();
1752 bool GLRenderer::isContextLost()
1754 return (m_context
->getGraphicsResetStatusARB() != GL_NO_ERROR
);