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"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/string_split.h"
14 #include "base/string_util.h"
15 #include "build/build_config.h"
16 #include "cc/compositor_frame.h"
17 #include "cc/compositor_frame_metadata.h"
18 #include "cc/damage_tracker.h"
19 #include "cc/geometry_binding.h"
20 #include "cc/gl_frame_data.h"
21 #include "cc/layer_quad.h"
22 #include "cc/math_util.h"
23 #include "cc/priority_calculator.h"
25 #include "cc/render_pass.h"
26 #include "cc/render_surface_filters.h"
27 #include "cc/scoped_resource.h"
28 #include "cc/single_thread_proxy.h"
29 #include "cc/stream_video_draw_quad.h"
30 #include "cc/texture_draw_quad.h"
31 #include "cc/video_layer_impl.h"
32 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
33 #include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
34 #include "third_party/khronos/GLES2/gl2.h"
35 #include "third_party/khronos/GLES2/gl2ext.h"
36 #include "third_party/skia/include/core/SkBitmap.h"
37 #include "third_party/skia/include/core/SkColor.h"
38 #include "third_party/skia/include/gpu/GrContext.h"
39 #include "third_party/skia/include/gpu/GrTexture.h"
40 #include "third_party/skia/include/gpu/SkGpuDevice.h"
41 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h"
42 #include "ui/gfx/quad_f.h"
43 #include "ui/gfx/rect_conversions.h"
46 using WebKit::WebGraphicsContext3D
;
47 using WebKit::WebGraphicsMemoryAllocation
;
48 using WebKit::WebSharedGraphicsContext3D
;
54 bool needsIOSurfaceReadbackWorkaround()
56 #if defined(OS_MACOSX)
63 } // anonymous namespace
65 scoped_ptr
<GLRenderer
> GLRenderer::create(RendererClient
* client
, OutputSurface
* outputSurface
, ResourceProvider
* resourceProvider
)
67 scoped_ptr
<GLRenderer
> renderer(make_scoped_ptr(new GLRenderer(client
, outputSurface
, resourceProvider
)));
68 if (!renderer
->initialize())
69 return scoped_ptr
<GLRenderer
>();
71 return renderer
.Pass();
74 GLRenderer::GLRenderer(RendererClient
* client
, OutputSurface
* outputSurface
, ResourceProvider
* resourceProvider
)
75 : DirectRenderer(client
, resourceProvider
)
76 , m_offscreenFramebufferId(0)
77 , m_sharedGeometryQuad(gfx::RectF(-0.5f
, -0.5f
, 1.0f
, 1.0f
))
78 , m_outputSurface(outputSurface
)
79 , m_context(outputSurface
->Context3D())
80 , m_isViewportChanged(false)
81 , m_isBackbufferDiscarded(false)
82 , m_discardBackbufferWhenNotVisible(false)
83 , m_isUsingBindUniform(false)
85 , m_isScissorEnabled(false)
90 bool GLRenderer::initialize()
92 if (!m_context
->makeContextCurrent())
95 m_context
->setContextLostCallback(this);
96 m_context
->pushGroupMarkerEXT("CompositorContext");
98 std::string extensionsString
= UTF16ToASCII(m_context
->getString(GL_EXTENSIONS
));
99 std::vector
<std::string
> extensionsList
;
100 base::SplitString(extensionsString
, ' ', &extensionsList
);
101 std::set
<string
> extensions(extensionsList
.begin(), extensionsList
.end());
103 if (settings().acceleratePainting
&& extensions
.count("GL_EXT_texture_format_BGRA8888")
104 && extensions
.count("GL_EXT_read_format_bgra"))
105 m_capabilities
.usingAcceleratedPainting
= true;
107 m_capabilities
.usingAcceleratedPainting
= false;
109 m_capabilities
.usingPartialSwap
= settings().partialSwapEnabled
&& extensions
.count("GL_CHROMIUM_post_sub_buffer");
111 // Use the swapBuffers callback only with the threaded proxy.
112 if (m_client
->hasImplThread())
113 m_capabilities
.usingSwapCompleteCallback
= extensions
.count("GL_CHROMIUM_swapbuffers_complete_callback");
114 if (m_capabilities
.usingSwapCompleteCallback
)
115 m_context
->setSwapBuffersCompleteCallbackCHROMIUM(this);
117 m_capabilities
.usingSetVisibility
= extensions
.count("GL_CHROMIUM_set_visibility");
119 if (extensions
.count("GL_CHROMIUM_iosurface"))
120 DCHECK(extensions
.count("GL_ARB_texture_rectangle"));
122 m_capabilities
.usingGpuMemoryManager
= extensions
.count("GL_CHROMIUM_gpu_memory_manager");
123 if (m_capabilities
.usingGpuMemoryManager
)
124 m_context
->setMemoryAllocationChangedCallbackCHROMIUM(this);
126 m_capabilities
.usingDiscardBackbuffer
= extensions
.count("GL_CHROMIUM_discard_backbuffer");
128 m_capabilities
.usingEglImage
= extensions
.count("GL_OES_EGL_image_external");
130 m_capabilities
.maxTextureSize
= m_resourceProvider
->maxTextureSize();
131 m_capabilities
.bestTextureFormat
= m_resourceProvider
->bestTextureFormat();
133 // The updater can access textures while the GLRenderer is using them.
134 m_capabilities
.allowPartialTextureUpdates
= true;
136 m_isUsingBindUniform
= extensions
.count("GL_CHROMIUM_bind_uniform_location");
138 // Make sure scissoring starts as disabled.
139 GLC(m_context
, m_context
->disable(GL_SCISSOR_TEST
));
140 DCHECK(!m_isScissorEnabled
);
142 if (!initializeSharedObjects())
145 // Make sure the viewport and context gets initialized, even if it is to zero.
150 GLRenderer::~GLRenderer()
152 m_context
->setSwapBuffersCompleteCallbackCHROMIUM(0);
153 m_context
->setMemoryAllocationChangedCallbackCHROMIUM(0);
154 m_context
->setContextLostCallback(0);
155 cleanupSharedObjects();
158 const RendererCapabilities
& GLRenderer::capabilities() const
160 return m_capabilities
;
163 WebGraphicsContext3D
* GLRenderer::context()
168 void GLRenderer::debugGLCall(WebGraphicsContext3D
* context
, const char* command
, const char* file
, int line
)
170 unsigned long error
= context
->getError();
171 if (error
!= GL_NO_ERROR
)
172 LOG(ERROR
) << "GL command failed: File: " << file
<< "\n\tLine " << line
<< "\n\tcommand: " << command
<< ", error " << static_cast<int>(error
) << "\n";
175 void GLRenderer::setVisible(bool visible
)
177 if (m_visible
== visible
)
181 enforceMemoryPolicy();
183 // TODO: Replace setVisibilityCHROMIUM with an extension to explicitly manage front/backbuffers
185 if (m_capabilities
.usingSetVisibility
)
186 m_context
->setVisibilityCHROMIUM(visible
);
189 void GLRenderer::sendManagedMemoryStats(size_t bytesVisible
, size_t bytesVisibleAndNearby
, size_t bytesAllocated
)
191 WebKit::WebGraphicsManagedMemoryStats stats
;
192 stats
.bytesVisible
= bytesVisible
;
193 stats
.bytesVisibleAndNearby
= bytesVisibleAndNearby
;
194 stats
.bytesAllocated
= bytesAllocated
;
195 stats
.backbufferRequested
= !m_isBackbufferDiscarded
;
196 m_context
->sendManagedMemoryStatsCHROMIUM(&stats
);
199 void GLRenderer::releaseRenderPassTextures()
201 m_renderPassTextures
.clear();
204 void GLRenderer::viewportChanged()
206 m_isViewportChanged
= true;
209 void GLRenderer::clearFramebuffer(DrawingFrame
& frame
)
211 // On DEBUG builds, opaque render passes are cleared to blue to easily see regions that were not drawn on the screen.
212 if (frame
.currentRenderPass
->has_transparent_background
)
213 GLC(m_context
, m_context
->clearColor(0, 0, 0, 0));
215 GLC(m_context
, m_context
->clearColor(0, 0, 1, 1));
218 if (frame
.currentRenderPass
->has_transparent_background
)
220 m_context
->clear(GL_COLOR_BUFFER_BIT
);
223 void GLRenderer::beginDrawingFrame(DrawingFrame
& frame
)
225 // FIXME: Remove this once backbuffer is automatically recreated on first use
228 if (viewportSize().IsEmpty())
231 TRACE_EVENT0("cc", "GLRenderer::drawLayers");
232 if (m_isViewportChanged
) {
233 // Only reshape when we know we are going to draw. Otherwise, the reshape
234 // can leave the window at the wrong size if we never draw and the proper
235 // viewport size is never set.
236 m_isViewportChanged
= false;
237 m_context
->reshape(viewportWidth(), viewportHeight());
240 makeContextCurrent();
241 // Bind the common vertex attributes used for drawing all the layers.
242 m_sharedGeometry
->prepareForDraw();
244 GLC(m_context
, m_context
->disable(GL_DEPTH_TEST
));
245 GLC(m_context
, m_context
->disable(GL_CULL_FACE
));
246 GLC(m_context
, m_context
->colorMask(true, true, true, true));
247 GLC(m_context
, m_context
->enable(GL_BLEND
));
248 m_blendShadow
= true;
249 GLC(m_context
, m_context
->blendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
));
250 GLC(context(), context()->activeTexture(GL_TEXTURE0
));
254 void GLRenderer::doNoOp()
256 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, 0));
257 GLC(m_context
, m_context
->flush());
260 void GLRenderer::drawQuad(DrawingFrame
& frame
, const DrawQuad
* quad
)
262 DCHECK(quad
->rect
.Contains(quad
->visible_rect
));
263 if (quad
->material
!= DrawQuad::TEXTURE_CONTENT
) {
264 flushTextureQuadCache();
265 setBlendEnabled(quad
->ShouldDrawWithBlending());
268 switch (quad
->material
) {
269 case DrawQuad::INVALID
:
272 case DrawQuad::CHECKERBOARD
:
273 drawCheckerboardQuad(frame
, CheckerboardDrawQuad::MaterialCast(quad
));
275 case DrawQuad::DEBUG_BORDER
:
276 drawDebugBorderQuad(frame
, DebugBorderDrawQuad::MaterialCast(quad
));
278 case DrawQuad::IO_SURFACE_CONTENT
:
279 drawIOSurfaceQuad(frame
, IOSurfaceDrawQuad::MaterialCast(quad
));
281 case DrawQuad::RENDER_PASS
:
282 drawRenderPassQuad(frame
, RenderPassDrawQuad::MaterialCast(quad
));
284 case DrawQuad::SOLID_COLOR
:
285 drawSolidColorQuad(frame
, SolidColorDrawQuad::MaterialCast(quad
));
287 case DrawQuad::STREAM_VIDEO_CONTENT
:
288 drawStreamVideoQuad(frame
, StreamVideoDrawQuad::MaterialCast(quad
));
290 case DrawQuad::TEXTURE_CONTENT
:
291 enqueueTextureQuad(frame
, TextureDrawQuad::MaterialCast(quad
));
293 case DrawQuad::TILED_CONTENT
:
294 drawTileQuad(frame
, TileDrawQuad::MaterialCast(quad
));
296 case DrawQuad::YUV_VIDEO_CONTENT
:
297 drawYUVVideoQuad(frame
, YUVVideoDrawQuad::MaterialCast(quad
));
302 void GLRenderer::drawCheckerboardQuad(const DrawingFrame
& frame
, const CheckerboardDrawQuad
* quad
)
304 const TileCheckerboardProgram
* program
= tileCheckerboardProgram();
305 DCHECK(program
&& (program
->initialized() || isContextLost()));
306 setUseProgram(program
->program());
308 SkColor color
= quad
->color
;
309 GLC(context(), context()->uniform4f(program
->fragmentShader().colorLocation(), SkColorGetR(color
) / 255.0, SkColorGetG(color
) / 255.0, SkColorGetB(color
) / 255.0, 1));
311 const int checkerboardWidth
= 16;
312 float frequency
= 1.0 / checkerboardWidth
;
314 gfx::Rect tileRect
= quad
->rect
;
315 float texOffsetX
= tileRect
.x() % checkerboardWidth
;
316 float texOffsetY
= tileRect
.y() % checkerboardWidth
;
317 float texScaleX
= tileRect
.width();
318 float texScaleY
= tileRect
.height();
319 GLC(context(), context()->uniform4f(program
->fragmentShader().texTransformLocation(), texOffsetX
, texOffsetY
, texScaleX
, texScaleY
));
321 GLC(context(), context()->uniform1f(program
->fragmentShader().frequencyLocation(), frequency
));
323 setShaderOpacity(quad
->opacity(), program
->fragmentShader().alphaLocation());
324 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
327 void GLRenderer::drawDebugBorderQuad(const DrawingFrame
& frame
, const DebugBorderDrawQuad
* quad
)
329 static float glMatrix
[16];
330 const SolidColorProgram
* program
= solidColorProgram();
331 DCHECK(program
&& (program
->initialized() || isContextLost()));
332 setUseProgram(program
->program());
334 // Use the full quadRect for debug quads to not move the edges based on partial swaps.
335 const gfx::Rect
& layerRect
= quad
->rect
;
336 gfx::Transform renderMatrix
= quad
->quadTransform();
337 renderMatrix
.Translate(0.5 * layerRect
.width() + layerRect
.x(), 0.5 * layerRect
.height() + layerRect
.y());
338 renderMatrix
.Scale(layerRect
.width(), layerRect
.height());
339 GLRenderer::toGLMatrix(&glMatrix
[0], frame
.projectionMatrix
* renderMatrix
);
340 GLC(context(), context()->uniformMatrix4fv(program
->vertexShader().matrixLocation(), 1, false, &glMatrix
[0]));
342 SkColor color
= quad
->color
;
343 float alpha
= SkColorGetA(color
) / 255.0;
345 GLC(context(), context()->uniform4f(program
->fragmentShader().colorLocation(), (SkColorGetR(color
) / 255.0) * alpha
, (SkColorGetG(color
) / 255.0) * alpha
, (SkColorGetB(color
) / 255.0) * alpha
, alpha
));
347 GLC(context(), context()->lineWidth(quad
->width
));
349 // The indices for the line are stored in the same array as the triangle indices.
350 GLC(context(), context()->drawElements(GL_LINE_LOOP
, 4, GL_UNSIGNED_SHORT
, 0));
353 static WebGraphicsContext3D
* getFilterContext(bool hasImplThread
)
356 return WebSharedGraphicsContext3D::compositorThreadContext();
358 return WebSharedGraphicsContext3D::mainThreadContext();
361 static GrContext
* getFilterGrContext(bool hasImplThread
)
364 return WebSharedGraphicsContext3D::compositorThreadGrContext();
366 return WebSharedGraphicsContext3D::mainThreadGrContext();
369 static inline SkBitmap
applyFilters(GLRenderer
* renderer
, const WebKit::WebFilterOperations
& filters
, ScopedResource
* sourceTexture
, bool hasImplThread
)
371 if (filters
.isEmpty())
374 WebGraphicsContext3D
* filterContext
= getFilterContext(hasImplThread
);
375 GrContext
* filterGrContext
= getFilterGrContext(hasImplThread
);
377 if (!filterContext
|| !filterGrContext
)
380 renderer
->context()->flush();
382 ResourceProvider::ScopedWriteLockGL
lock(renderer
->resourceProvider(), sourceTexture
->id());
383 SkBitmap source
= RenderSurfaceFilters::apply(filters
, lock
.textureId(), sourceTexture
->size(), filterContext
, filterGrContext
);
387 static SkBitmap
applyImageFilter(GLRenderer
* renderer
, SkImageFilter
* filter
, ScopedResource
* sourceTexture
, bool hasImplThread
)
392 WebGraphicsContext3D
* context3d
= getFilterContext(hasImplThread
);
393 GrContext
* grContext
= getFilterGrContext(hasImplThread
);
395 if (!context3d
|| !grContext
)
398 renderer
->context()->flush();
400 ResourceProvider::ScopedWriteLockGL
lock(renderer
->resourceProvider(), sourceTexture
->id());
402 // Wrap the source texture in a Ganesh platform texture.
403 GrPlatformTextureDesc platformTextureDescription
;
404 platformTextureDescription
.fWidth
= sourceTexture
->size().width();
405 platformTextureDescription
.fHeight
= sourceTexture
->size().height();
406 platformTextureDescription
.fConfig
= kSkia8888_GrPixelConfig
;
407 platformTextureDescription
.fTextureHandle
= lock
.textureId();
408 skia::RefPtr
<GrTexture
> texture
= skia::AdoptRef(grContext
->createPlatformTexture(platformTextureDescription
));
410 // Place the platform texture inside an SkBitmap.
412 source
.setConfig(SkBitmap::kARGB_8888_Config
, sourceTexture
->size().width(), sourceTexture
->size().height());
413 skia::RefPtr
<SkGrPixelRef
> pixelRef
= skia::AdoptRef(new SkGrPixelRef(texture
.get()));
414 source
.setPixelRef(pixelRef
.get());
416 // Create a scratch texture for backing store.
418 desc
.fFlags
= kRenderTarget_GrTextureFlagBit
| kNoStencil_GrTextureFlagBit
;
420 desc
.fWidth
= source
.width();
421 desc
.fHeight
= source
.height();
422 desc
.fConfig
= kSkia8888_GrPixelConfig
;
423 GrAutoScratchTexture
scratchTexture(grContext
, desc
, GrContext::kExact_ScratchTexMatch
);
424 skia::RefPtr
<GrTexture
> backingStore
= skia::AdoptRef(scratchTexture
.detach());
426 // Create a device and canvas using that backing store.
427 SkGpuDevice
device(grContext
, backingStore
.get());
428 SkCanvas
canvas(&device
);
430 // Draw the source bitmap through the filter to the canvas.
432 paint
.setImageFilter(filter
);
434 canvas
.drawSprite(source
, 0, 0, &paint
);
437 return device
.accessBitmap(false);
440 scoped_ptr
<ScopedResource
> GLRenderer::drawBackgroundFilters(
441 DrawingFrame
& frame
, const RenderPassDrawQuad
* quad
,
442 const WebKit::WebFilterOperations
& filters
,
443 const gfx::Transform
& contentsDeviceTransform
,
444 const gfx::Transform
& contentsDeviceTransformInverse
)
446 // This method draws a background filter, which applies a filter to any pixels behind the quad and seen through its background.
447 // The algorithm works as follows:
448 // 1. Compute a bounding box around the pixels that will be visible through the quad.
449 // 2. Read the pixels in the bounding box into a buffer R.
450 // 3. Apply the background filter to R, so that it is applied in the pixels' coordinate space.
451 // 4. Apply the quad's inverse transform to map the pixels in R into the quad's content space. This implicitly
452 // clips R by the content bounds of the quad since the destination texture has bounds matching the quad's content.
453 // 5. Draw the background texture for the contents using the same transform as used to draw the contents itself. This is done
454 // without blending to replace the current background pixels with the new filtered background.
455 // 6. Draw the contents of the quad over drop of the new background with blending, as per usual. The filtered background
456 // pixels will show through any non-opaque pixels in this draws.
458 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
460 // FIXME: When this algorithm changes, update LayerTreeHost::prioritizeTextures() accordingly.
462 if (filters
.isEmpty())
463 return scoped_ptr
<ScopedResource
>();
465 // FIXME: We only allow background filters on an opaque render surface because other surfaces may contain
466 // translucent pixels, and the contents behind those translucent pixels wouldn't have the filter applied.
467 if (frame
.currentRenderPass
->has_transparent_background
)
468 return scoped_ptr
<ScopedResource
>();
469 DCHECK(!frame
.currentTexture
);
471 // FIXME: Do a single readback for both the surface and replica and cache the filtered results (once filter textures are not reused).
472 gfx::Rect deviceRect
= gfx::ToEnclosingRect(MathUtil::mapClippedRect(contentsDeviceTransform
, sharedGeometryQuad().BoundingBox()));
474 int top
, right
, bottom
, left
;
475 filters
.getOutsets(top
, right
, bottom
, left
);
476 deviceRect
.Inset(-left
, -top
, -right
, -bottom
);
478 deviceRect
.Intersect(frame
.currentRenderPass
->output_rect
);
480 scoped_ptr
<ScopedResource
> deviceBackgroundTexture
= ScopedResource::create(m_resourceProvider
);
481 if (!getFramebufferTexture(deviceBackgroundTexture
.get(), deviceRect
))
482 return scoped_ptr
<ScopedResource
>();
484 SkBitmap filteredDeviceBackground
= applyFilters(this, filters
, deviceBackgroundTexture
.get(), m_client
->hasImplThread());
485 if (!filteredDeviceBackground
.getTexture())
486 return scoped_ptr
<ScopedResource
>();
488 GrTexture
* texture
= reinterpret_cast<GrTexture
*>(filteredDeviceBackground
.getTexture());
489 int filteredDeviceBackgroundTextureId
= texture
->getTextureHandle();
491 scoped_ptr
<ScopedResource
> backgroundTexture
= ScopedResource::create(m_resourceProvider
);
492 if (!backgroundTexture
->Allocate(quad
->rect
.size(), GL_RGBA
, ResourceProvider::TextureUsageFramebuffer
))
493 return scoped_ptr
<ScopedResource
>();
495 const RenderPass
* targetRenderPass
= frame
.currentRenderPass
;
496 bool usingBackgroundTexture
= useScopedTexture(frame
, backgroundTexture
.get(), quad
->rect
);
498 if (usingBackgroundTexture
) {
499 // Copy the readback pixels from device to the background texture for the surface.
500 gfx::Transform deviceToFramebufferTransform
;
501 deviceToFramebufferTransform
.Translate(quad
->rect
.width() / 2.0, quad
->rect
.height() / 2.0);
502 deviceToFramebufferTransform
.Scale(quad
->rect
.width(), quad
->rect
.height());
503 deviceToFramebufferTransform
.PreconcatTransform(contentsDeviceTransformInverse
);
504 copyTextureToFramebuffer(frame
, filteredDeviceBackgroundTextureId
, deviceRect
, deviceToFramebufferTransform
);
507 useRenderPass(frame
, targetRenderPass
);
509 if (!usingBackgroundTexture
)
510 return scoped_ptr
<ScopedResource
>();
511 return backgroundTexture
.Pass();
514 void GLRenderer::drawRenderPassQuad(DrawingFrame
& frame
, const RenderPassDrawQuad
* quad
)
516 CachedResource
* contentsTexture
= m_renderPassTextures
.get(quad
->render_pass_id
);
517 if (!contentsTexture
|| !contentsTexture
->id())
520 const RenderPass
* renderPass
= frame
.renderPassesById
->get(quad
->render_pass_id
);
525 gfx::Transform quadRectMatrix
;
526 quadRectTransform(&quadRectMatrix
, quad
->quadTransform(), quad
->rect
);
527 gfx::Transform contentsDeviceTransform
= MathUtil::to2dTransform(frame
.windowMatrix
* frame
.projectionMatrix
* quadRectMatrix
);
529 // Can only draw surface if device matrix is invertible.
530 if (!contentsDeviceTransform
.IsInvertible())
533 gfx::Transform contentsDeviceTransformInverse
= MathUtil::inverse(contentsDeviceTransform
);
534 scoped_ptr
<ScopedResource
> backgroundTexture
= drawBackgroundFilters(
535 frame
, quad
, renderPass
->background_filters
,
536 contentsDeviceTransform
, contentsDeviceTransformInverse
);
538 // FIXME: Cache this value so that we don't have to do it for both the surface and its replica.
539 // Apply filters to the contents texture.
540 SkBitmap filterBitmap
;
541 if (renderPass
->filter
) {
542 filterBitmap
= applyImageFilter(this, renderPass
->filter
.get(), contentsTexture
, m_client
->hasImplThread());
544 filterBitmap
= applyFilters(this, renderPass
->filters
, contentsTexture
, m_client
->hasImplThread());
547 // Draw the background texture if there is one.
548 if (backgroundTexture
) {
549 DCHECK(backgroundTexture
->size() == quad
->rect
.size());
550 ResourceProvider::ScopedReadLockGL
lock(m_resourceProvider
, backgroundTexture
->id());
551 copyTextureToFramebuffer(frame
, lock
.textureId(), quad
->rect
, quad
->quadTransform());
554 bool clipped
= false;
555 gfx::QuadF deviceQuad
= MathUtil::mapQuad(contentsDeviceTransform
, sharedGeometryQuad(), clipped
);
557 LayerQuad deviceLayerBounds
= LayerQuad(gfx::QuadF(deviceQuad
.BoundingBox()));
558 LayerQuad deviceLayerEdges
= LayerQuad(deviceQuad
);
560 // Use anti-aliasing programs only when necessary.
561 bool useAA
= (!deviceQuad
.IsRectilinear() || !deviceQuad
.BoundingBox().IsExpressibleAsRect());
563 deviceLayerBounds
.inflateAntiAliasingDistance();
564 deviceLayerEdges
.inflateAntiAliasingDistance();
567 scoped_ptr
<ResourceProvider::ScopedReadLockGL
> maskResourceLock
;
568 unsigned maskTextureId
= 0;
569 if (quad
->mask_resource_id
) {
570 maskResourceLock
.reset(new ResourceProvider::ScopedReadLockGL(m_resourceProvider
, quad
->mask_resource_id
));
571 maskTextureId
= maskResourceLock
->textureId();
574 // FIXME: use the backgroundTexture and blend the background in with this draw instead of having a separate copy of the background texture.
576 scoped_ptr
<ResourceProvider::ScopedReadLockGL
> contentsResourceLock
;
577 if (filterBitmap
.getTexture()) {
578 GrTexture
* texture
= reinterpret_cast<GrTexture
*>(filterBitmap
.getTexture());
579 context()->bindTexture(GL_TEXTURE_2D
, texture
->getTextureHandle());
581 contentsResourceLock
= make_scoped_ptr(new ResourceProvider::ScopedSamplerGL(m_resourceProvider
, contentsTexture
->id(),
582 GL_TEXTURE_2D
, GL_LINEAR
));
584 int shaderQuadLocation
= -1;
585 int shaderEdgeLocation
= -1;
586 int shaderMaskSamplerLocation
= -1;
587 int shaderMaskTexCoordScaleLocation
= -1;
588 int shaderMaskTexCoordOffsetLocation
= -1;
589 int shaderMatrixLocation
= -1;
590 int shaderAlphaLocation
= -1;
591 int shaderTexTransformLocation
= -1;
592 int shaderTexScaleLocation
= -1;
594 if (useAA
&& maskTextureId
) {
595 const RenderPassMaskProgramAA
* program
= renderPassMaskProgramAA();
596 setUseProgram(program
->program());
597 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
599 shaderQuadLocation
= program
->vertexShader().pointLocation();
600 shaderEdgeLocation
= program
->fragmentShader().edgeLocation();
601 shaderMaskSamplerLocation
= program
->fragmentShader().maskSamplerLocation();
602 shaderMaskTexCoordScaleLocation
= program
->fragmentShader().maskTexCoordScaleLocation();
603 shaderMaskTexCoordOffsetLocation
= program
->fragmentShader().maskTexCoordOffsetLocation();
604 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
605 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
606 shaderTexScaleLocation
= program
->vertexShader().texScaleLocation();
607 } else if (!useAA
&& maskTextureId
) {
608 const RenderPassMaskProgram
* program
= renderPassMaskProgram();
609 setUseProgram(program
->program());
610 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
612 shaderMaskSamplerLocation
= program
->fragmentShader().maskSamplerLocation();
613 shaderMaskTexCoordScaleLocation
= program
->fragmentShader().maskTexCoordScaleLocation();
614 shaderMaskTexCoordOffsetLocation
= program
->fragmentShader().maskTexCoordOffsetLocation();
615 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
616 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
617 shaderTexTransformLocation
= program
->vertexShader().texTransformLocation();
618 } else if (useAA
&& !maskTextureId
) {
619 const RenderPassProgramAA
* program
= renderPassProgramAA();
620 setUseProgram(program
->program());
621 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
623 shaderQuadLocation
= program
->vertexShader().pointLocation();
624 shaderEdgeLocation
= program
->fragmentShader().edgeLocation();
625 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
626 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
627 shaderTexScaleLocation
= program
->vertexShader().texScaleLocation();
629 const RenderPassProgram
* program
= renderPassProgram();
630 setUseProgram(program
->program());
631 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
633 shaderMatrixLocation
= program
->vertexShader().matrixLocation();
634 shaderAlphaLocation
= program
->fragmentShader().alphaLocation();
635 shaderTexTransformLocation
= program
->vertexShader().texTransformLocation();
638 float tex_scale_x
= quad
->rect
.width() / static_cast<float>(contentsTexture
->size().width());
639 float tex_scale_y
= quad
->rect
.height() / static_cast<float>(contentsTexture
->size().height());
640 DCHECK_LE(tex_scale_x
, 1.0f
);
641 DCHECK_LE(tex_scale_y
, 1.0f
);
643 if (shaderTexTransformLocation
!= -1) {
644 GLC(context(), context()->uniform4f(shaderTexTransformLocation
,
646 tex_scale_x
, tex_scale_y
));
647 } else if (shaderTexScaleLocation
!= -1) {
648 GLC(context(), context()->uniform2f(shaderTexScaleLocation
,
649 tex_scale_x
, tex_scale_y
));
654 if (shaderMaskSamplerLocation
!= -1) {
655 DCHECK(shaderMaskTexCoordScaleLocation
!= 1);
656 DCHECK(shaderMaskTexCoordOffsetLocation
!= 1);
657 GLC(context(), context()->activeTexture(GL_TEXTURE1
));
658 GLC(context(), context()->uniform1i(shaderMaskSamplerLocation
, 1));
659 GLC(context(), context()->uniform2f(shaderMaskTexCoordOffsetLocation
,
660 quad
->mask_uv_rect
.x(), quad
->mask_uv_rect
.y()));
661 GLC(context(), context()->uniform2f(shaderMaskTexCoordScaleLocation
,
662 quad
->mask_uv_rect
.width() / tex_scale_x
, quad
->mask_uv_rect
.height() / tex_scale_y
));
663 m_resourceProvider
->bindForSampling(quad
->mask_resource_id
, GL_TEXTURE_2D
, GL_LINEAR
);
664 GLC(context(), context()->activeTexture(GL_TEXTURE0
));
667 if (shaderEdgeLocation
!= -1) {
669 deviceLayerEdges
.toFloatArray(edge
);
670 deviceLayerBounds
.toFloatArray(&edge
[12]);
671 GLC(context(), context()->uniform3fv(shaderEdgeLocation
, 8, edge
));
674 // 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.
675 gfx::QuadF surfaceQuad
= MathUtil::mapQuad(contentsDeviceTransformInverse
, deviceLayerEdges
.ToQuadF(), clipped
);
678 setShaderOpacity(quad
->opacity(), shaderAlphaLocation
);
679 setShaderQuadF(surfaceQuad
, shaderQuadLocation
);
680 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, shaderMatrixLocation
);
682 // Flush the compositor context before the filter bitmap goes out of
683 // scope, so the draw gets processed before the filter texture gets deleted.
684 if (filterBitmap
.getTexture())
688 void GLRenderer::drawSolidColorQuad(const DrawingFrame
& frame
, const SolidColorDrawQuad
* quad
)
690 const SolidColorProgram
* program
= solidColorProgram();
691 setUseProgram(program
->program());
693 SkColor color
= quad
->color
;
694 float opacity
= quad
->opacity();
695 float alpha
= (SkColorGetA(color
) / 255.0) * opacity
;
697 GLC(context(), context()->uniform4f(program
->fragmentShader().colorLocation(), (SkColorGetR(color
) / 255.0) * alpha
, (SkColorGetG(color
) / 255.0) * alpha
, (SkColorGetB(color
) / 255.0) * alpha
, alpha
));
699 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
702 struct TileProgramUniforms
{
704 unsigned samplerLocation
;
705 unsigned vertexTexTransformLocation
;
706 unsigned fragmentTexTransformLocation
;
707 unsigned edgeLocation
;
708 unsigned matrixLocation
;
709 unsigned alphaLocation
;
710 unsigned pointLocation
;
714 static void tileUniformLocation(T program
, TileProgramUniforms
& uniforms
)
716 uniforms
.program
= program
->program();
717 uniforms
.vertexTexTransformLocation
= program
->vertexShader().vertexTexTransformLocation();
718 uniforms
.matrixLocation
= program
->vertexShader().matrixLocation();
719 uniforms
.pointLocation
= program
->vertexShader().pointLocation();
721 uniforms
.samplerLocation
= program
->fragmentShader().samplerLocation();
722 uniforms
.alphaLocation
= program
->fragmentShader().alphaLocation();
723 uniforms
.fragmentTexTransformLocation
= program
->fragmentShader().fragmentTexTransformLocation();
724 uniforms
.edgeLocation
= program
->fragmentShader().edgeLocation();
727 void GLRenderer::drawTileQuad(const DrawingFrame
& frame
, const TileDrawQuad
* quad
)
729 gfx::Rect tileRect
= quad
->visible_rect
;
731 gfx::RectF texCoordRect
= quad
->tex_coord_rect
;
732 float texToGeomScaleX
= quad
->rect
.width() / texCoordRect
.width();
733 float texToGeomScaleY
= quad
->rect
.height() / texCoordRect
.height();
735 // texCoordRect corresponds to quadRect, but quadVisibleRect may be
736 // smaller than quadRect due to occlusion or clipping. Adjust
737 // texCoordRect to match.
738 gfx::Vector2d topLeftDiff
= tileRect
.origin() - quad
->rect
.origin();
739 gfx::Vector2d bottomRightDiff
=
740 tileRect
.bottom_right() - quad
->rect
.bottom_right();
741 texCoordRect
.Inset(topLeftDiff
.x() / texToGeomScaleX
,
742 topLeftDiff
.y() / texToGeomScaleY
,
743 -bottomRightDiff
.x() / texToGeomScaleX
,
744 -bottomRightDiff
.y() / texToGeomScaleY
);
746 gfx::RectF
clampGeomRect(tileRect
);
747 gfx::RectF
clampTexRect(texCoordRect
);
748 // Clamp texture coordinates to avoid sampling outside the layer
749 // by deflating the tile region half a texel or half a texel
750 // minus epsilon for one pixel layers. The resulting clamp region
751 // is mapped to the unit square by the vertex shader and mapped
752 // back to normalized texture coordinates by the fragment shader
753 // after being clamped to 0-1 range.
754 const float epsilon
= 1 / 1024.0f
;
755 float texClampX
= std::min(0.5f
, 0.5f
* clampTexRect
.width() - epsilon
);
756 float texClampY
= std::min(0.5f
, 0.5f
* clampTexRect
.height() - epsilon
);
757 float geomClampX
= std::min(texClampX
* texToGeomScaleX
,
758 0.5f
* clampGeomRect
.width() - epsilon
);
759 float geomClampY
= std::min(texClampY
* texToGeomScaleY
,
760 0.5f
* clampGeomRect
.height() - epsilon
);
761 clampGeomRect
.Inset(geomClampX
, geomClampY
, geomClampX
, geomClampY
);
762 clampTexRect
.Inset(texClampX
, texClampY
, texClampX
, texClampY
);
764 // Map clamping rectangle to unit square.
765 float vertexTexTranslateX
= -clampGeomRect
.x() / clampGeomRect
.width();
766 float vertexTexTranslateY
= -clampGeomRect
.y() / clampGeomRect
.height();
767 float vertexTexScaleX
= tileRect
.width() / clampGeomRect
.width();
768 float vertexTexScaleY
= tileRect
.height() / clampGeomRect
.height();
770 // Map to normalized texture coordinates.
771 const gfx::Size
& textureSize
= quad
->texture_size
;
772 float fragmentTexTranslateX
= clampTexRect
.x() / textureSize
.width();
773 float fragmentTexTranslateY
= clampTexRect
.y() / textureSize
.height();
774 float fragmentTexScaleX
= clampTexRect
.width() / textureSize
.width();
775 float fragmentTexScaleY
= clampTexRect
.height() / textureSize
.height();
778 gfx::QuadF localQuad
;
779 gfx::Transform deviceTransform
= MathUtil::to2dTransform(frame
.windowMatrix
* frame
.projectionMatrix
* quad
->quadTransform());
780 if (!deviceTransform
.IsInvertible())
783 bool clipped
= false;
784 gfx::QuadF deviceLayerQuad
= MathUtil::mapQuad(deviceTransform
, gfx::QuadF(quad
->visibleContentRect()), clipped
);
787 TileProgramUniforms uniforms
;
788 // For now, we simply skip anti-aliasing with the quad is clipped. This only happens
789 // on perspective transformed layers that go partially behind the camera.
790 if (quad
->IsAntialiased() && !clipped
) {
791 if (quad
->swizzle_contents
)
792 tileUniformLocation(tileProgramSwizzleAA(), uniforms
);
794 tileUniformLocation(tileProgramAA(), uniforms
);
796 if (quad
->ShouldDrawWithBlending()) {
797 if (quad
->swizzle_contents
)
798 tileUniformLocation(tileProgramSwizzle(), uniforms
);
800 tileUniformLocation(tileProgram(), uniforms
);
802 if (quad
->swizzle_contents
)
803 tileUniformLocation(tileProgramSwizzleOpaque(), uniforms
);
805 tileUniformLocation(tileProgramOpaque(), uniforms
);
809 setUseProgram(uniforms
.program
);
810 GLC(context(), context()->uniform1i(uniforms
.samplerLocation
, 0));
811 bool scaled
= (texToGeomScaleX
!= 1 || texToGeomScaleY
!= 1);
812 GLenum filter
= (quad
->IsAntialiased() || scaled
|| !quad
->quadTransform().IsIdentityOrIntegerTranslation()) ? GL_LINEAR
: GL_NEAREST
;
813 ResourceProvider::ScopedSamplerGL
quadResourceLock(m_resourceProvider
, quad
->resource_id
, GL_TEXTURE_2D
, filter
);
815 bool useAA
= !clipped
&& quad
->IsAntialiased();
817 LayerQuad deviceLayerBounds
= LayerQuad(gfx::QuadF(deviceLayerQuad
.BoundingBox()));
818 deviceLayerBounds
.inflateAntiAliasingDistance();
820 LayerQuad deviceLayerEdges
= LayerQuad(deviceLayerQuad
);
821 deviceLayerEdges
.inflateAntiAliasingDistance();
824 deviceLayerEdges
.toFloatArray(edge
);
825 deviceLayerBounds
.toFloatArray(&edge
[12]);
826 GLC(context(), context()->uniform3fv(uniforms
.edgeLocation
, 8, edge
));
828 GLC(context(), context()->uniform4f(uniforms
.vertexTexTransformLocation
, vertexTexTranslateX
, vertexTexTranslateY
, vertexTexScaleX
, vertexTexScaleY
));
829 GLC(context(), context()->uniform4f(uniforms
.fragmentTexTransformLocation
, fragmentTexTranslateX
, fragmentTexTranslateY
, fragmentTexScaleX
, fragmentTexScaleY
));
831 gfx::PointF bottomRight
= tileRect
.bottom_right();
832 gfx::PointF bottomLeft
= tileRect
.bottom_left();
833 gfx::PointF topLeft
= tileRect
.origin();
834 gfx::PointF topRight
= tileRect
.top_right();
836 // Map points to device space.
837 bottomRight
= MathUtil::mapPoint(deviceTransform
, bottomRight
, clipped
);
839 bottomLeft
= MathUtil::mapPoint(deviceTransform
, bottomLeft
, clipped
);
841 topLeft
= MathUtil::mapPoint(deviceTransform
, topLeft
, clipped
);
843 topRight
= MathUtil::mapPoint(deviceTransform
, topRight
, clipped
);
846 LayerQuad::Edge
bottomEdge(bottomRight
, bottomLeft
);
847 LayerQuad::Edge
leftEdge(bottomLeft
, topLeft
);
848 LayerQuad::Edge
topEdge(topLeft
, topRight
);
849 LayerQuad::Edge
rightEdge(topRight
, bottomRight
);
851 // Only apply anti-aliasing to edges not clipped by culling or scissoring.
852 if (quad
->top_edge_aa
&& tileRect
.y() == quad
->rect
.y())
853 topEdge
= deviceLayerEdges
.top();
854 if (quad
->left_edge_aa
&& tileRect
.x() == quad
->rect
.x())
855 leftEdge
= deviceLayerEdges
.left();
856 if (quad
->right_edge_aa
&& tileRect
.right() == quad
->rect
.right())
857 rightEdge
= deviceLayerEdges
.right();
858 if (quad
->bottom_edge_aa
&& tileRect
.bottom() == quad
->rect
.bottom())
859 bottomEdge
= deviceLayerEdges
.bottom();
861 float sign
= gfx::QuadF(tileRect
).IsCounterClockwise() ? -1 : 1;
862 bottomEdge
.scale(sign
);
863 leftEdge
.scale(sign
);
865 rightEdge
.scale(sign
);
867 // Create device space quad.
868 LayerQuad
deviceQuad(leftEdge
, topEdge
, rightEdge
, bottomEdge
);
870 // 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.
871 gfx::Transform deviceTransformInverse
= MathUtil::inverse(deviceTransform
);
872 localQuad
= MathUtil::mapQuad(deviceTransformInverse
, deviceQuad
.ToQuadF(), clipped
);
874 // We should not DCHECK(!clipped) here, because anti-aliasing inflation may cause deviceQuad to become
875 // clipped. To our knowledge this scenario does not need to be handled differently than the unclipped case.
877 // Move fragment shader transform to vertex shader. We can do this while
878 // still producing correct results as fragmentTexTransformLocation
879 // should always be non-negative when tiles are transformed in a way
880 // that could result in sampling outside the layer.
881 vertexTexScaleX
*= fragmentTexScaleX
;
882 vertexTexScaleY
*= fragmentTexScaleY
;
883 vertexTexTranslateX
*= fragmentTexScaleX
;
884 vertexTexTranslateY
*= fragmentTexScaleY
;
885 vertexTexTranslateX
+= fragmentTexTranslateX
;
886 vertexTexTranslateY
+= fragmentTexTranslateY
;
888 GLC(context(), context()->uniform4f(uniforms
.vertexTexTransformLocation
, vertexTexTranslateX
, vertexTexTranslateY
, vertexTexScaleX
, vertexTexScaleY
));
890 localQuad
= gfx::RectF(tileRect
);
893 // Normalize to tileRect.
894 localQuad
.Scale(1.0f
/ tileRect
.width(), 1.0f
/ tileRect
.height());
896 setShaderOpacity(quad
->opacity(), uniforms
.alphaLocation
);
897 setShaderQuadF(localQuad
, uniforms
.pointLocation
);
899 // The tile quad shader behaves differently compared to all other shaders.
900 // The transform and vertex data are used to figure out the extents that the
901 // un-antialiased quad should have and which vertex this is and the float
902 // quad passed in via uniform is the actual geometry that gets used to draw
903 // it. This is why this centered rect is used and not the original quadRect.
904 gfx::RectF
centeredRect(gfx::PointF(-0.5 * tileRect
.width(), -0.5 * tileRect
.height()), tileRect
.size());
905 drawQuadGeometry(frame
, quad
->quadTransform(), centeredRect
, uniforms
.matrixLocation
);
908 void GLRenderer::drawYUVVideoQuad(const DrawingFrame
& frame
, const YUVVideoDrawQuad
* quad
)
910 const VideoYUVProgram
* program
= videoYUVProgram();
911 DCHECK(program
&& (program
->initialized() || isContextLost()));
913 const VideoLayerImpl::FramePlane
& yPlane
= quad
->y_plane
;
914 const VideoLayerImpl::FramePlane
& uPlane
= quad
->u_plane
;
915 const VideoLayerImpl::FramePlane
& vPlane
= quad
->v_plane
;
917 GLC(context(), context()->activeTexture(GL_TEXTURE1
));
918 ResourceProvider::ScopedSamplerGL
yPlaneLock(m_resourceProvider
, yPlane
.resourceId
, GL_TEXTURE_2D
, GL_LINEAR
);
919 GLC(context(), context()->activeTexture(GL_TEXTURE2
));
920 ResourceProvider::ScopedSamplerGL
uPlaneLock(m_resourceProvider
, uPlane
.resourceId
, GL_TEXTURE_2D
, GL_LINEAR
);
921 GLC(context(), context()->activeTexture(GL_TEXTURE3
));
922 ResourceProvider::ScopedSamplerGL
vPlaneLock(m_resourceProvider
, vPlane
.resourceId
, GL_TEXTURE_2D
, GL_LINEAR
);
924 setUseProgram(program
->program());
926 GLC(context(), context()->uniform2f(program
->vertexShader().texScaleLocation(), quad
->tex_scale
.width(), quad
->tex_scale
.height()));
927 GLC(context(), context()->uniform1i(program
->fragmentShader().yTextureLocation(), 1));
928 GLC(context(), context()->uniform1i(program
->fragmentShader().uTextureLocation(), 2));
929 GLC(context(), context()->uniform1i(program
->fragmentShader().vTextureLocation(), 3));
931 // These values are magic numbers that are used in the transformation from YUV to RGB color values.
932 // They are taken from the following webpage: http://www.fourcc.org/fccyvrgb.php
934 1.164f
, 1.164f
, 1.164f
,
938 GLC(context(), context()->uniformMatrix3fv(program
->fragmentShader().yuvMatrixLocation(), 1, 0, yuv2RGB
));
940 // These values map to 16, 128, and 128 respectively, and are computed
941 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
942 // They are used in the YUV to RGBA conversion formula:
943 // Y - 16 : Gives 16 values of head and footroom for overshooting
944 // U - 128 : Turns unsigned U into signed U [-128,127]
945 // V - 128 : Turns unsigned V into signed V [-128,127]
946 float yuvAdjust
[3] = {
951 GLC(context(), context()->uniform3fv(program
->fragmentShader().yuvAdjLocation(), 1, yuvAdjust
));
953 setShaderOpacity(quad
->opacity(), program
->fragmentShader().alphaLocation());
954 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
956 // Reset active texture back to texture 0.
957 GLC(context(), context()->activeTexture(GL_TEXTURE0
));
960 void GLRenderer::drawStreamVideoQuad(const DrawingFrame
& frame
, const StreamVideoDrawQuad
* quad
)
962 static float glMatrix
[16];
964 DCHECK(m_capabilities
.usingEglImage
);
966 const VideoStreamTextureProgram
* program
= videoStreamTextureProgram();
967 setUseProgram(program
->program());
969 toGLMatrix(&glMatrix
[0], quad
->matrix
);
970 GLC(context(), context()->uniformMatrix4fv(program
->vertexShader().texMatrixLocation(), 1, false, glMatrix
));
972 GLC(context(), context()->bindTexture(GL_TEXTURE_EXTERNAL_OES
, quad
->texture_id
));
974 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
976 setShaderOpacity(quad
->opacity(), program
->fragmentShader().alphaLocation());
977 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, program
->vertexShader().matrixLocation());
980 struct TextureProgramBinding
{
981 template<class Program
> void set(
982 Program
* program
, WebKit::WebGraphicsContext3D
* context
)
984 DCHECK(program
&& (program
->initialized() || context
->isContextLost()));
985 programId
= program
->program();
986 samplerLocation
= program
->fragmentShader().samplerLocation();
987 matrixLocation
= program
->vertexShader().matrixLocation();
988 alphaLocation
= program
->fragmentShader().alphaLocation();
996 struct TexTransformTextureProgramBinding
: TextureProgramBinding
{
997 template<class Program
> void set(
998 Program
* program
, WebKit::WebGraphicsContext3D
* context
)
1000 TextureProgramBinding::set(program
, context
);
1001 texTransformLocation
= program
->vertexShader().texTransformLocation();
1002 vertexOpacityLocation
= program
->vertexShader().vertexOpacityLocation();
1004 int texTransformLocation
;
1005 int vertexOpacityLocation
;
1008 void GLRenderer::flushTextureQuadCache()
1010 // Check to see if we have anything to draw.
1011 if (m_drawCache
.program_id
== 0)
1014 // Set the correct blending mode.
1015 setBlendEnabled(m_drawCache
.needs_blending
);
1017 // Bind the program to the GL state.
1018 setUseProgram(m_drawCache
.program_id
);
1020 // Bind the correct texture sampler location.
1021 GLC(context(), context()->uniform1i(m_drawCache
.sampler_location
, 0));
1023 // Assume the current active textures is 0.
1024 ResourceProvider::ScopedReadLockGL
lockedQuad(m_resourceProvider
, m_drawCache
.resource_id
);
1025 GLC(context(), context()->bindTexture(GL_TEXTURE_2D
, lockedQuad
.textureId()));
1027 // set up premultiplied alpha.
1028 if (!m_drawCache
.use_premultiplied_alpha
) {
1029 // As it turns out, the premultiplied alpha blending function (ONE, ONE_MINUS_SRC_ALPHA)
1030 // will never cause the alpha channel to be set to anything less than 1.0 if it is
1031 // initialized to that value! Therefore, premultipliedAlpha being false is the first
1032 // situation we can generally see an alpha channel less than 1.0 coming out of the
1033 // compositor. This is causing platform differences in some layout tests (see
1034 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use a separate
1035 // blend function for the alpha channel to avoid modifying it. Don't use colorMask for this
1036 // as it has performance implications on some platforms.
1037 GLC(context(), context()->blendFuncSeparate(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, GL_ZERO
, GL_ONE
));
1040 COMPILE_ASSERT(sizeof(Float4
) == 4 * sizeof(float), struct_is_densely_packed
);
1041 COMPILE_ASSERT(sizeof(Float16
) == 16 * sizeof(float), struct_is_densely_packed
);
1043 // Upload the tranforms for both points and uvs.
1044 GLC(m_context
, m_context
->uniformMatrix4fv(static_cast<int>(m_drawCache
.matrix_location
), static_cast<int>(m_drawCache
.matrix_data
.size()), false, reinterpret_cast<float*>(&m_drawCache
.matrix_data
.front())));
1045 GLC(m_context
, m_context
->uniform4fv(static_cast<int>(m_drawCache
.uv_xform_location
), static_cast<int>(m_drawCache
.uv_xform_data
.size()), reinterpret_cast<float*>(&m_drawCache
.uv_xform_data
.front())));
1046 GLC(m_context
, m_context
->uniform1fv(static_cast<int>(m_drawCache
.vertex_opacity_location
), static_cast<int>(m_drawCache
.vertex_opacity_data
.size()), static_cast<float*>(&m_drawCache
.vertex_opacity_data
.front())));
1049 GLC(m_context
, m_context
->drawElements(GL_TRIANGLES
, 6 * m_drawCache
.matrix_data
.size(), GL_UNSIGNED_SHORT
, 0));
1051 // Clean up after ourselves (reset state set above).
1052 if (!m_drawCache
.use_premultiplied_alpha
)
1053 GLC(m_context
, m_context
->blendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
));
1056 m_drawCache
.program_id
= 0;
1057 m_drawCache
.uv_xform_data
.resize(0);
1058 m_drawCache
.vertex_opacity_data
.resize(0);
1059 m_drawCache
.matrix_data
.resize(0);
1062 void GLRenderer::enqueueTextureQuad(const DrawingFrame
& frame
, const TextureDrawQuad
* quad
)
1064 // Choose the correct texture program binding
1065 TexTransformTextureProgramBinding binding
;
1067 binding
.set(textureProgramFlip(), context());
1069 binding
.set(textureProgram(), context());
1071 int resourceID
= quad
->resource_id
;
1073 if (m_drawCache
.program_id
!= binding
.programId
||
1074 m_drawCache
.resource_id
!= resourceID
||
1075 m_drawCache
.use_premultiplied_alpha
!= quad
->premultiplied_alpha
||
1076 m_drawCache
.needs_blending
!= quad
->ShouldDrawWithBlending() ||
1077 m_drawCache
.matrix_data
.size() >= 8) {
1078 flushTextureQuadCache();
1079 m_drawCache
.program_id
= binding
.programId
;
1080 m_drawCache
.resource_id
= resourceID
;
1081 m_drawCache
.use_premultiplied_alpha
= quad
->premultiplied_alpha
;
1082 m_drawCache
.needs_blending
= quad
->ShouldDrawWithBlending();
1084 m_drawCache
.uv_xform_location
= binding
.texTransformLocation
;
1085 m_drawCache
.vertex_opacity_location
= binding
.vertexOpacityLocation
;
1086 m_drawCache
.matrix_location
= binding
.matrixLocation
;
1087 m_drawCache
.sampler_location
= binding
.samplerLocation
;
1090 // Generate the uv-transform
1091 const gfx::RectF
& uvRect
= quad
->uv_rect
;
1092 Float4 uv
= {uvRect
.x(), uvRect
.y(), uvRect
.width(), uvRect
.height()};
1093 m_drawCache
.uv_xform_data
.push_back(uv
);
1095 // Generate the vertex opacity
1096 const float opacity
= quad
->opacity();
1097 m_drawCache
.vertex_opacity_data
.push_back(quad
->vertex_opacity
[0] * opacity
);
1098 m_drawCache
.vertex_opacity_data
.push_back(quad
->vertex_opacity
[1] * opacity
);
1099 m_drawCache
.vertex_opacity_data
.push_back(quad
->vertex_opacity
[2] * opacity
);
1100 m_drawCache
.vertex_opacity_data
.push_back(quad
->vertex_opacity
[3] * opacity
);
1102 // Generate the transform matrix
1103 gfx::Transform quadRectMatrix
;
1104 quadRectTransform(&quadRectMatrix
, quad
->quadTransform(), quad
->rect
);
1105 quadRectMatrix
= frame
.projectionMatrix
* quadRectMatrix
;
1108 quadRectMatrix
.matrix().asColMajorf(m
.data
);
1109 m_drawCache
.matrix_data
.push_back(m
);
1112 void GLRenderer::drawTextureQuad(const DrawingFrame
& frame
, const TextureDrawQuad
* quad
)
1114 TexTransformTextureProgramBinding binding
;
1116 binding
.set(textureProgramFlip(), context());
1118 binding
.set(textureProgram(), context());
1119 setUseProgram(binding
.programId
);
1120 GLC(context(), context()->uniform1i(binding
.samplerLocation
, 0));
1121 const gfx::RectF
& uvRect
= quad
->uv_rect
;
1122 GLC(context(), context()->uniform4f(binding
.texTransformLocation
, uvRect
.x(), uvRect
.y(), uvRect
.width(), uvRect
.height()));
1124 GLC(context(), context()->uniform1fv(binding
.vertexOpacityLocation
, 4, quad
->vertex_opacity
));
1126 ResourceProvider::ScopedSamplerGL
quadResourceLock(m_resourceProvider
, quad
->resource_id
, GL_TEXTURE_2D
, GL_LINEAR
);
1128 if (!quad
->premultiplied_alpha
) {
1129 // As it turns out, the premultiplied alpha blending function (ONE, ONE_MINUS_SRC_ALPHA)
1130 // will never cause the alpha channel to be set to anything less than 1.0 if it is
1131 // initialized to that value! Therefore, premultipliedAlpha being false is the first
1132 // situation we can generally see an alpha channel less than 1.0 coming out of the
1133 // compositor. This is causing platform differences in some layout tests (see
1134 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use a separate
1135 // blend function for the alpha channel to avoid modifying it. Don't use colorMask for this
1136 // as it has performance implications on some platforms.
1137 GLC(context(), context()->blendFuncSeparate(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
, GL_ZERO
, GL_ONE
));
1140 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, binding
.matrixLocation
);
1142 if (!quad
->premultiplied_alpha
)
1143 GLC(m_context
, m_context
->blendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
));
1146 void GLRenderer::drawIOSurfaceQuad(const DrawingFrame
& frame
, const IOSurfaceDrawQuad
* quad
)
1148 TexTransformTextureProgramBinding binding
;
1149 binding
.set(textureIOSurfaceProgram(), context());
1151 setUseProgram(binding
.programId
);
1152 GLC(context(), context()->uniform1i(binding
.samplerLocation
, 0));
1153 if (quad
->orientation
== IOSurfaceDrawQuad::FLIPPED
)
1154 GLC(context(), context()->uniform4f(binding
.texTransformLocation
, 0, quad
->io_surface_size
.height(), quad
->io_surface_size
.width(), quad
->io_surface_size
.height() * -1.0));
1156 GLC(context(), context()->uniform4f(binding
.texTransformLocation
, 0, 0, quad
->io_surface_size
.width(), quad
->io_surface_size
.height()));
1158 const float vertex_opacity
[] = {quad
->opacity(), quad
->opacity(), quad
->opacity(), quad
->opacity()};
1159 GLC(context(), context()->uniform1fv(binding
.vertexOpacityLocation
, 4, vertex_opacity
));
1161 GLC(context(), context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB
, quad
->io_surface_texture_id
));
1163 drawQuadGeometry(frame
, quad
->quadTransform(), quad
->rect
, binding
.matrixLocation
);
1165 GLC(context(), context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB
, 0));
1168 void GLRenderer::finishDrawingFrame(DrawingFrame
& frame
)
1170 m_currentFramebufferLock
.reset();
1171 m_swapBufferRect
.Union(gfx::ToEnclosingRect(frame
.rootDamageRect
));
1173 GLC(m_context
, m_context
->disable(GL_BLEND
));
1174 m_blendShadow
= false;
1176 if (settings().compositorFrameMessage
) {
1177 CompositorFrame compositor_frame
;
1178 compositor_frame
.metadata
= m_client
->makeCompositorFrameMetadata();
1179 compositor_frame
.gl_frame_data
.reset(new GLFrameData());
1180 // FIXME: Fill in GLFrameData when we implement swapping with it.
1181 m_outputSurface
->SendFrameToParentCompositor(compositor_frame
);
1185 void GLRenderer::finishDrawingQuadList()
1187 flushTextureQuadCache();
1190 bool GLRenderer::flippedFramebuffer() const
1195 void GLRenderer::ensureScissorTestEnabled()
1197 if (m_isScissorEnabled
)
1200 flushTextureQuadCache();
1201 GLC(m_context
, m_context
->enable(GL_SCISSOR_TEST
));
1202 m_isScissorEnabled
= true;
1205 void GLRenderer::ensureScissorTestDisabled()
1207 if (!m_isScissorEnabled
)
1210 flushTextureQuadCache();
1211 GLC(m_context
, m_context
->disable(GL_SCISSOR_TEST
));
1212 m_isScissorEnabled
= false;
1215 void GLRenderer::toGLMatrix(float* glMatrix
, const gfx::Transform
& transform
)
1217 transform
.matrix().asColMajorf(glMatrix
);
1220 void GLRenderer::setShaderQuadF(const gfx::QuadF
& quad
, int quadLocation
)
1222 if (quadLocation
== -1)
1226 point
[0] = quad
.p1().x();
1227 point
[1] = quad
.p1().y();
1228 point
[2] = quad
.p2().x();
1229 point
[3] = quad
.p2().y();
1230 point
[4] = quad
.p3().x();
1231 point
[5] = quad
.p3().y();
1232 point
[6] = quad
.p4().x();
1233 point
[7] = quad
.p4().y();
1234 GLC(m_context
, m_context
->uniform2fv(quadLocation
, 4, point
));
1237 void GLRenderer::setShaderOpacity(float opacity
, int alphaLocation
)
1239 if (alphaLocation
!= -1)
1240 GLC(m_context
, m_context
->uniform1f(alphaLocation
, opacity
));
1243 void GLRenderer::setBlendEnabled(bool enabled
)
1245 if (enabled
== m_blendShadow
)
1249 GLC(m_context
, m_context
->enable(GL_BLEND
));
1251 GLC(m_context
, m_context
->disable(GL_BLEND
));
1252 m_blendShadow
= enabled
;
1255 void GLRenderer::setUseProgram(unsigned program
)
1257 if (program
== m_programShadow
)
1259 GLC(m_context
, m_context
->useProgram(program
));
1260 m_programShadow
= program
;
1263 void GLRenderer::drawQuadGeometry(const DrawingFrame
& frame
, const gfx::Transform
& drawTransform
, const gfx::RectF
& quadRect
, int matrixLocation
)
1265 gfx::Transform quadRectMatrix
;
1266 quadRectTransform(&quadRectMatrix
, drawTransform
, quadRect
);
1267 static float glMatrix
[16];
1268 toGLMatrix(&glMatrix
[0], frame
.projectionMatrix
* quadRectMatrix
);
1269 GLC(m_context
, m_context
->uniformMatrix4fv(matrixLocation
, 1, false, &glMatrix
[0]));
1271 GLC(m_context
, m_context
->drawElements(GL_TRIANGLES
, 6, GL_UNSIGNED_SHORT
, 0));
1274 void GLRenderer::copyTextureToFramebuffer(const DrawingFrame
& frame
, int textureId
, const gfx::Rect
& rect
, const gfx::Transform
& drawMatrix
)
1276 const RenderPassProgram
* program
= renderPassProgram();
1278 GLC(context(), context()->bindTexture(GL_TEXTURE_2D
, textureId
));
1280 setUseProgram(program
->program());
1281 GLC(context(), context()->uniform1i(program
->fragmentShader().samplerLocation(), 0));
1282 GLC(context(), context()->uniform4f(program
->vertexShader().texTransformLocation(),
1283 0.0f
, 0.0f
, 1.0f
, 1.0f
));
1284 setShaderOpacity(1, program
->fragmentShader().alphaLocation());
1285 drawQuadGeometry(frame
, drawMatrix
, rect
, program
->vertexShader().matrixLocation());
1288 void GLRenderer::finish()
1290 TRACE_EVENT0("cc", "GLRenderer::finish");
1291 m_context
->finish();
1294 bool GLRenderer::swapBuffers()
1297 DCHECK(!m_isBackbufferDiscarded
);
1299 TRACE_EVENT0("cc", "GLRenderer::swapBuffers");
1300 // We're done! Time to swapbuffers!
1302 if (m_capabilities
.usingPartialSwap
) {
1303 // If supported, we can save significant bandwidth by only swapping the damaged/scissored region (clamped to the viewport)
1304 m_swapBufferRect
.Intersect(gfx::Rect(gfx::Point(), viewportSize()));
1305 int flippedYPosOfRectBottom
= viewportHeight() - m_swapBufferRect
.y() - m_swapBufferRect
.height();
1306 m_context
->postSubBufferCHROMIUM(m_swapBufferRect
.x(), flippedYPosOfRectBottom
, m_swapBufferRect
.width(), m_swapBufferRect
.height());
1308 // Note that currently this has the same effect as swapBuffers; we should
1309 // consider exposing a different entry point on WebGraphicsContext3D.
1310 m_context
->prepareTexture();
1313 m_swapBufferRect
= gfx::Rect();
1318 void GLRenderer::onSwapBuffersComplete()
1320 m_client
->onSwapBuffersComplete();
1323 void GLRenderer::onMemoryAllocationChanged(WebGraphicsMemoryAllocation allocation
)
1325 // Just ignore the memory manager when it says to set the limit to zero
1326 // bytes. This will happen when the memory manager thinks that the renderer
1327 // is not visible (which the renderer knows better).
1328 if (allocation
.bytesLimitWhenVisible
) {
1329 ManagedMemoryPolicy
policy(
1330 allocation
.bytesLimitWhenVisible
,
1331 priorityCutoffValue(allocation
.priorityCutoffWhenVisible
),
1332 allocation
.bytesLimitWhenNotVisible
,
1333 priorityCutoffValue(allocation
.priorityCutoffWhenNotVisible
));
1335 if (allocation
.enforceButDoNotKeepAsPolicy
)
1336 m_client
->enforceManagedMemoryPolicy(policy
);
1338 m_client
->setManagedMemoryPolicy(policy
);
1341 bool oldDiscardBackbufferWhenNotVisible
= m_discardBackbufferWhenNotVisible
;
1342 m_discardBackbufferWhenNotVisible
= !allocation
.suggestHaveBackbuffer
;
1343 enforceMemoryPolicy();
1344 if (allocation
.enforceButDoNotKeepAsPolicy
)
1345 m_discardBackbufferWhenNotVisible
= oldDiscardBackbufferWhenNotVisible
;
1348 int GLRenderer::priorityCutoffValue(WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priorityCutoff
)
1350 switch (priorityCutoff
) {
1351 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing
:
1352 return PriorityCalculator::allowNothingCutoff();
1353 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly
:
1354 return PriorityCalculator::allowVisibleOnlyCutoff();
1355 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleAndNearby
:
1356 return PriorityCalculator::allowVisibleAndNearbyCutoff();
1357 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything
:
1358 return PriorityCalculator::allowEverythingCutoff();
1364 void GLRenderer::enforceMemoryPolicy()
1367 TRACE_EVENT0("cc", "GLRenderer::enforceMemoryPolicy dropping resources");
1368 releaseRenderPassTextures();
1369 if (m_discardBackbufferWhenNotVisible
)
1370 discardBackbuffer();
1371 GLC(m_context
, m_context
->flush());
1375 void GLRenderer::discardBackbuffer()
1377 if (m_isBackbufferDiscarded
)
1380 if (!m_capabilities
.usingDiscardBackbuffer
)
1383 m_context
->discardBackbufferCHROMIUM();
1384 m_isBackbufferDiscarded
= true;
1386 // Damage tracker needs a full reset every time framebuffer is discarded.
1387 m_client
->setFullRootLayerDamage();
1390 void GLRenderer::ensureBackbuffer()
1392 if (!m_isBackbufferDiscarded
)
1395 if (!m_capabilities
.usingDiscardBackbuffer
)
1398 m_context
->ensureBackbufferCHROMIUM();
1399 m_isBackbufferDiscarded
= false;
1402 void GLRenderer::onContextLost()
1404 m_client
->didLoseOutputSurface();
1408 void GLRenderer::getFramebufferPixels(void *pixels
, const gfx::Rect
& rect
)
1410 DCHECK(rect
.right() <= viewportWidth());
1411 DCHECK(rect
.bottom() <= viewportHeight());
1416 makeContextCurrent();
1418 bool doWorkaround
= needsIOSurfaceReadbackWorkaround();
1420 GLuint temporaryTexture
= 0;
1421 GLuint temporaryFBO
= 0;
1424 // On Mac OS X, calling glReadPixels against an FBO whose color attachment is an
1425 // IOSurface-backed texture causes corruption of future glReadPixels calls, even those on
1426 // different OpenGL contexts. It is believed that this is the root cause of top crasher
1427 // http://crbug.com/99393. <rdar://problem/10949687>
1429 temporaryTexture
= m_context
->createTexture();
1430 GLC(m_context
, m_context
->bindTexture(GL_TEXTURE_2D
, temporaryTexture
));
1431 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
));
1432 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
));
1433 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
));
1434 GLC(m_context
, m_context
->texParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
));
1435 // Copy the contents of the current (IOSurface-backed) framebuffer into a temporary texture.
1436 GLC(m_context
, m_context
->copyTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, 0, 0, viewportSize().width(), viewportSize().height(), 0));
1437 temporaryFBO
= m_context
->createFramebuffer();
1438 // Attach this texture to an FBO, and perform the readback from that FBO.
1439 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, temporaryFBO
));
1440 GLC(m_context
, m_context
->framebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, temporaryTexture
, 0));
1442 DCHECK(m_context
->checkFramebufferStatus(GL_FRAMEBUFFER
) == GL_FRAMEBUFFER_COMPLETE
);
1445 scoped_array
<uint8_t> srcPixels(new uint8_t[rect
.width() * rect
.height() * 4]);
1446 GLC(m_context
, m_context
->readPixels(rect
.x(), viewportSize().height() - rect
.bottom(), rect
.width(), rect
.height(),
1447 GL_RGBA
, GL_UNSIGNED_BYTE
, srcPixels
.get()));
1449 uint8_t* destPixels
= static_cast<uint8_t*>(pixels
);
1450 size_t rowBytes
= rect
.width() * 4;
1451 int numRows
= rect
.height();
1452 size_t totalBytes
= numRows
* rowBytes
;
1453 for (size_t destY
= 0; destY
< totalBytes
; destY
+= rowBytes
) {
1455 size_t srcY
= totalBytes
- destY
- rowBytes
;
1456 // Swizzle BGRA -> RGBA.
1457 for (size_t x
= 0; x
< rowBytes
; x
+= 4) {
1458 destPixels
[destY
+ (x
+0)] = srcPixels
.get()[srcY
+ (x
+2)];
1459 destPixels
[destY
+ (x
+1)] = srcPixels
.get()[srcY
+ (x
+1)];
1460 destPixels
[destY
+ (x
+2)] = srcPixels
.get()[srcY
+ (x
+0)];
1461 destPixels
[destY
+ (x
+3)] = srcPixels
.get()[srcY
+ (x
+3)];
1467 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, 0));
1468 GLC(m_context
, m_context
->bindTexture(GL_TEXTURE_2D
, 0));
1469 GLC(m_context
, m_context
->deleteFramebuffer(temporaryFBO
));
1470 GLC(m_context
, m_context
->deleteTexture(temporaryTexture
));
1473 enforceMemoryPolicy();
1476 bool GLRenderer::getFramebufferTexture(ScopedResource
* texture
, const gfx::Rect
& deviceRect
)
1478 DCHECK(!texture
->id() || (texture
->size() == deviceRect
.size() && texture
->format() == GL_RGB
));
1480 if (!texture
->id() && !texture
->Allocate(deviceRect
.size(), GL_RGB
, ResourceProvider::TextureUsageAny
))
1483 ResourceProvider::ScopedWriteLockGL
lock(m_resourceProvider
, texture
->id());
1484 GLC(m_context
, m_context
->bindTexture(GL_TEXTURE_2D
, lock
.textureId()));
1485 GLC(m_context
, m_context
->copyTexImage2D(GL_TEXTURE_2D
, 0, texture
->format(),
1486 deviceRect
.x(), deviceRect
.y(), deviceRect
.width(), deviceRect
.height(), 0));
1490 bool GLRenderer::useScopedTexture(DrawingFrame
& frame
, const ScopedResource
* texture
, const gfx::Rect
& viewportRect
)
1492 DCHECK(texture
->id());
1493 frame
.currentRenderPass
= 0;
1494 frame
.currentTexture
= texture
;
1496 return bindFramebufferToTexture(frame
, texture
, viewportRect
);
1499 void GLRenderer::bindFramebufferToOutputSurface(DrawingFrame
& frame
)
1501 m_currentFramebufferLock
.reset();
1502 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, 0));
1505 bool GLRenderer::bindFramebufferToTexture(DrawingFrame
& frame
, const ScopedResource
* texture
, const gfx::Rect
& framebufferRect
)
1507 DCHECK(texture
->id());
1509 GLC(m_context
, m_context
->bindFramebuffer(GL_FRAMEBUFFER
, m_offscreenFramebufferId
));
1510 m_currentFramebufferLock
= make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL(m_resourceProvider
, texture
->id()));
1511 unsigned textureId
= m_currentFramebufferLock
->textureId();
1512 GLC(m_context
, m_context
->framebufferTexture2D(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, textureId
, 0));
1514 DCHECK(m_context
->checkFramebufferStatus(GL_FRAMEBUFFER
) == GL_FRAMEBUFFER_COMPLETE
);
1516 initializeMatrices(frame
, framebufferRect
, false);
1517 setDrawViewportSize(framebufferRect
.size());
1522 void GLRenderer::setScissorTestRect(const gfx::Rect
& scissorRect
)
1524 ensureScissorTestEnabled();
1526 // Don't unnecessarily ask the context to change the scissor, because it
1527 // may cause undesired GPU pipeline flushes.
1528 if (scissorRect
== m_scissorRect
)
1531 m_scissorRect
= scissorRect
;
1532 flushTextureQuadCache();
1533 GLC(m_context
, m_context
->scissor(scissorRect
.x(), scissorRect
.y(), scissorRect
.width(), scissorRect
.height()));
1536 void GLRenderer::setDrawViewportSize(const gfx::Size
& viewportSize
)
1538 GLC(m_context
, m_context
->viewport(0, 0, viewportSize
.width(), viewportSize
.height()));
1541 bool GLRenderer::makeContextCurrent()
1543 return m_context
->makeContextCurrent();
1546 bool GLRenderer::initializeSharedObjects()
1548 TRACE_EVENT0("cc", "GLRenderer::initializeSharedObjects");
1549 makeContextCurrent();
1551 // Create an FBO for doing offscreen rendering.
1552 GLC(m_context
, m_offscreenFramebufferId
= m_context
->createFramebuffer());
1554 // We will always need these programs to render, so create the programs eagerly so that the shader compilation can
1555 // start while we do other work. Other programs are created lazily on first access.
1556 m_sharedGeometry
= make_scoped_ptr(new GeometryBinding(m_context
, quadVertexRect()));
1557 m_renderPassProgram
= make_scoped_ptr(new RenderPassProgram(m_context
));
1558 m_tileProgram
= make_scoped_ptr(new TileProgram(m_context
));
1559 m_tileProgramOpaque
= make_scoped_ptr(new TileProgramOpaque(m_context
));
1561 GLC(m_context
, m_context
->flush());
1566 const GLRenderer::TileCheckerboardProgram
* GLRenderer::tileCheckerboardProgram()
1568 if (!m_tileCheckerboardProgram
)
1569 m_tileCheckerboardProgram
= make_scoped_ptr(new TileCheckerboardProgram(m_context
));
1570 if (!m_tileCheckerboardProgram
->initialized()) {
1571 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
1572 m_tileCheckerboardProgram
->initialize(m_context
, m_isUsingBindUniform
);
1574 return m_tileCheckerboardProgram
.get();
1577 const GLRenderer::SolidColorProgram
* GLRenderer::solidColorProgram()
1579 if (!m_solidColorProgram
)
1580 m_solidColorProgram
= make_scoped_ptr(new SolidColorProgram(m_context
));
1581 if (!m_solidColorProgram
->initialized()) {
1582 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
1583 m_solidColorProgram
->initialize(m_context
, m_isUsingBindUniform
);
1585 return m_solidColorProgram
.get();
1588 const GLRenderer::RenderPassProgram
* GLRenderer::renderPassProgram()
1590 DCHECK(m_renderPassProgram
);
1591 if (!m_renderPassProgram
->initialized()) {
1592 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
1593 m_renderPassProgram
->initialize(m_context
, m_isUsingBindUniform
);
1595 return m_renderPassProgram
.get();
1598 const GLRenderer::RenderPassProgramAA
* GLRenderer::renderPassProgramAA()
1600 if (!m_renderPassProgramAA
)
1601 m_renderPassProgramAA
= make_scoped_ptr(new RenderPassProgramAA(m_context
));
1602 if (!m_renderPassProgramAA
->initialized()) {
1603 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
1604 m_renderPassProgramAA
->initialize(m_context
, m_isUsingBindUniform
);
1606 return m_renderPassProgramAA
.get();
1609 const GLRenderer::RenderPassMaskProgram
* GLRenderer::renderPassMaskProgram()
1611 if (!m_renderPassMaskProgram
)
1612 m_renderPassMaskProgram
= make_scoped_ptr(new RenderPassMaskProgram(m_context
));
1613 if (!m_renderPassMaskProgram
->initialized()) {
1614 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
1615 m_renderPassMaskProgram
->initialize(m_context
, m_isUsingBindUniform
);
1617 return m_renderPassMaskProgram
.get();
1620 const GLRenderer::RenderPassMaskProgramAA
* GLRenderer::renderPassMaskProgramAA()
1622 if (!m_renderPassMaskProgramAA
)
1623 m_renderPassMaskProgramAA
= make_scoped_ptr(new RenderPassMaskProgramAA(m_context
));
1624 if (!m_renderPassMaskProgramAA
->initialized()) {
1625 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
1626 m_renderPassMaskProgramAA
->initialize(m_context
, m_isUsingBindUniform
);
1628 return m_renderPassMaskProgramAA
.get();
1631 const GLRenderer::TileProgram
* GLRenderer::tileProgram()
1633 DCHECK(m_tileProgram
);
1634 if (!m_tileProgram
->initialized()) {
1635 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
1636 m_tileProgram
->initialize(m_context
, m_isUsingBindUniform
);
1638 return m_tileProgram
.get();
1641 const GLRenderer::TileProgramOpaque
* GLRenderer::tileProgramOpaque()
1643 DCHECK(m_tileProgramOpaque
);
1644 if (!m_tileProgramOpaque
->initialized()) {
1645 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
1646 m_tileProgramOpaque
->initialize(m_context
, m_isUsingBindUniform
);
1648 return m_tileProgramOpaque
.get();
1651 const GLRenderer::TileProgramAA
* GLRenderer::tileProgramAA()
1653 if (!m_tileProgramAA
)
1654 m_tileProgramAA
= make_scoped_ptr(new TileProgramAA(m_context
));
1655 if (!m_tileProgramAA
->initialized()) {
1656 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
1657 m_tileProgramAA
->initialize(m_context
, m_isUsingBindUniform
);
1659 return m_tileProgramAA
.get();
1662 const GLRenderer::TileProgramSwizzle
* GLRenderer::tileProgramSwizzle()
1664 if (!m_tileProgramSwizzle
)
1665 m_tileProgramSwizzle
= make_scoped_ptr(new TileProgramSwizzle(m_context
));
1666 if (!m_tileProgramSwizzle
->initialized()) {
1667 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
1668 m_tileProgramSwizzle
->initialize(m_context
, m_isUsingBindUniform
);
1670 return m_tileProgramSwizzle
.get();
1673 const GLRenderer::TileProgramSwizzleOpaque
* GLRenderer::tileProgramSwizzleOpaque()
1675 if (!m_tileProgramSwizzleOpaque
)
1676 m_tileProgramSwizzleOpaque
= make_scoped_ptr(new TileProgramSwizzleOpaque(m_context
));
1677 if (!m_tileProgramSwizzleOpaque
->initialized()) {
1678 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize");
1679 m_tileProgramSwizzleOpaque
->initialize(m_context
, m_isUsingBindUniform
);
1681 return m_tileProgramSwizzleOpaque
.get();
1684 const GLRenderer::TileProgramSwizzleAA
* GLRenderer::tileProgramSwizzleAA()
1686 if (!m_tileProgramSwizzleAA
)
1687 m_tileProgramSwizzleAA
= make_scoped_ptr(new TileProgramSwizzleAA(m_context
));
1688 if (!m_tileProgramSwizzleAA
->initialized()) {
1689 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
1690 m_tileProgramSwizzleAA
->initialize(m_context
, m_isUsingBindUniform
);
1692 return m_tileProgramSwizzleAA
.get();
1695 const GLRenderer::TextureProgram
* GLRenderer::textureProgram()
1697 if (!m_textureProgram
)
1698 m_textureProgram
= make_scoped_ptr(new TextureProgram(m_context
));
1699 if (!m_textureProgram
->initialized()) {
1700 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
1701 m_textureProgram
->initialize(m_context
, m_isUsingBindUniform
);
1703 return m_textureProgram
.get();
1706 const GLRenderer::TextureProgramFlip
* GLRenderer::textureProgramFlip()
1708 if (!m_textureProgramFlip
)
1709 m_textureProgramFlip
= make_scoped_ptr(new TextureProgramFlip(m_context
));
1710 if (!m_textureProgramFlip
->initialized()) {
1711 TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize");
1712 m_textureProgramFlip
->initialize(m_context
, m_isUsingBindUniform
);
1714 return m_textureProgramFlip
.get();
1717 const GLRenderer::TextureIOSurfaceProgram
* GLRenderer::textureIOSurfaceProgram()
1719 if (!m_textureIOSurfaceProgram
)
1720 m_textureIOSurfaceProgram
= make_scoped_ptr(new TextureIOSurfaceProgram(m_context
));
1721 if (!m_textureIOSurfaceProgram
->initialized()) {
1722 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
1723 m_textureIOSurfaceProgram
->initialize(m_context
, m_isUsingBindUniform
);
1725 return m_textureIOSurfaceProgram
.get();
1728 const GLRenderer::VideoYUVProgram
* GLRenderer::videoYUVProgram()
1730 if (!m_videoYUVProgram
)
1731 m_videoYUVProgram
= make_scoped_ptr(new VideoYUVProgram(m_context
));
1732 if (!m_videoYUVProgram
->initialized()) {
1733 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
1734 m_videoYUVProgram
->initialize(m_context
, m_isUsingBindUniform
);
1736 return m_videoYUVProgram
.get();
1739 const GLRenderer::VideoStreamTextureProgram
* GLRenderer::videoStreamTextureProgram()
1741 if (!m_videoStreamTextureProgram
)
1742 m_videoStreamTextureProgram
= make_scoped_ptr(new VideoStreamTextureProgram(m_context
));
1743 if (!m_videoStreamTextureProgram
->initialized()) {
1744 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
1745 m_videoStreamTextureProgram
->initialize(m_context
, m_isUsingBindUniform
);
1747 return m_videoStreamTextureProgram
.get();
1750 void GLRenderer::cleanupSharedObjects()
1752 makeContextCurrent();
1754 m_sharedGeometry
.reset();
1757 m_tileProgram
->cleanup(m_context
);
1758 if (m_tileProgramOpaque
)
1759 m_tileProgramOpaque
->cleanup(m_context
);
1760 if (m_tileProgramSwizzle
)
1761 m_tileProgramSwizzle
->cleanup(m_context
);
1762 if (m_tileProgramSwizzleOpaque
)
1763 m_tileProgramSwizzleOpaque
->cleanup(m_context
);
1764 if (m_tileProgramAA
)
1765 m_tileProgramAA
->cleanup(m_context
);
1766 if (m_tileProgramSwizzleAA
)
1767 m_tileProgramSwizzleAA
->cleanup(m_context
);
1768 if (m_tileCheckerboardProgram
)
1769 m_tileCheckerboardProgram
->cleanup(m_context
);
1771 if (m_renderPassMaskProgram
)
1772 m_renderPassMaskProgram
->cleanup(m_context
);
1773 if (m_renderPassProgram
)
1774 m_renderPassProgram
->cleanup(m_context
);
1775 if (m_renderPassMaskProgramAA
)
1776 m_renderPassMaskProgramAA
->cleanup(m_context
);
1777 if (m_renderPassProgramAA
)
1778 m_renderPassProgramAA
->cleanup(m_context
);
1780 if (m_textureProgram
)
1781 m_textureProgram
->cleanup(m_context
);
1782 if (m_textureProgramFlip
)
1783 m_textureProgramFlip
->cleanup(m_context
);
1784 if (m_textureIOSurfaceProgram
)
1785 m_textureIOSurfaceProgram
->cleanup(m_context
);
1787 if (m_videoYUVProgram
)
1788 m_videoYUVProgram
->cleanup(m_context
);
1789 if (m_videoStreamTextureProgram
)
1790 m_videoStreamTextureProgram
->cleanup(m_context
);
1792 if (m_solidColorProgram
)
1793 m_solidColorProgram
->cleanup(m_context
);
1795 if (m_offscreenFramebufferId
)
1796 GLC(m_context
, m_context
->deleteFramebuffer(m_offscreenFramebufferId
));
1798 releaseRenderPassTextures();
1801 bool GLRenderer::isContextLost()
1803 return (m_context
->getGraphicsResetStatusARB() != GL_NO_ERROR
);