Don't hide PopupZoomer if the content size didn't change.
[chromium-blink-merge.git] / cc / gl_renderer.cc
blobe9f8254a16b5629a6033aeb278a040d58821218d
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 <set>
8 #include <string>
9 #include <vector>
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"
24 #include "cc/proxy.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"
45 using namespace std;
46 using WebKit::WebGraphicsContext3D;
47 using WebKit::WebGraphicsMemoryAllocation;
48 using WebKit::WebSharedGraphicsContext3D;
50 namespace cc {
52 namespace {
54 bool needsIOSurfaceReadbackWorkaround()
56 #if defined(OS_MACOSX)
57 return true;
58 #else
59 return false;
60 #endif
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)
84 , m_visible(true)
85 , m_isScissorEnabled(false)
87 DCHECK(m_context);
90 bool GLRenderer::initialize()
92 if (!m_context->makeContextCurrent())
93 return false;
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;
106 else
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())
143 return false;
145 // Make sure the viewport and context gets initialized, even if it is to zero.
146 viewportChanged();
147 return true;
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()
165 return m_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)
178 return;
179 m_visible = visible;
181 enforceMemoryPolicy();
183 // TODO: Replace setVisibilityCHROMIUM with an extension to explicitly manage front/backbuffers
184 // crbug.com/116049
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));
214 else
215 GLC(m_context, m_context->clearColor(0, 0, 1, 1));
217 #ifdef NDEBUG
218 if (frame.currentRenderPass->has_transparent_background)
219 #endif
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
226 ensureBackbuffer();
228 if (viewportSize().IsEmpty())
229 return;
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));
251 m_programShadow = 0;
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:
270 NOTREACHED();
271 break;
272 case DrawQuad::CHECKERBOARD:
273 drawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad));
274 break;
275 case DrawQuad::DEBUG_BORDER:
276 drawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad));
277 break;
278 case DrawQuad::IO_SURFACE_CONTENT:
279 drawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad));
280 break;
281 case DrawQuad::RENDER_PASS:
282 drawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
283 break;
284 case DrawQuad::SOLID_COLOR:
285 drawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad));
286 break;
287 case DrawQuad::STREAM_VIDEO_CONTENT:
288 drawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad));
289 break;
290 case DrawQuad::TEXTURE_CONTENT:
291 enqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
292 break;
293 case DrawQuad::TILED_CONTENT:
294 drawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
295 break;
296 case DrawQuad::YUV_VIDEO_CONTENT:
297 drawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad));
298 break;
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)
355 if (hasImplThread)
356 return WebSharedGraphicsContext3D::compositorThreadContext();
357 else
358 return WebSharedGraphicsContext3D::mainThreadContext();
361 static GrContext* getFilterGrContext(bool hasImplThread)
363 if (hasImplThread)
364 return WebSharedGraphicsContext3D::compositorThreadGrContext();
365 else
366 return WebSharedGraphicsContext3D::mainThreadGrContext();
369 static inline SkBitmap applyFilters(GLRenderer* renderer, const WebKit::WebFilterOperations& filters, ScopedResource* sourceTexture, bool hasImplThread)
371 if (filters.isEmpty())
372 return SkBitmap();
374 WebGraphicsContext3D* filterContext = getFilterContext(hasImplThread);
375 GrContext* filterGrContext = getFilterGrContext(hasImplThread);
377 if (!filterContext || !filterGrContext)
378 return SkBitmap();
380 renderer->context()->flush();
382 ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourceTexture->id());
383 SkBitmap source = RenderSurfaceFilters::apply(filters, lock.textureId(), sourceTexture->size(), filterContext, filterGrContext);
384 return source;
387 static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, ScopedResource* sourceTexture, bool hasImplThread)
389 if (!filter)
390 return SkBitmap();
392 WebGraphicsContext3D* context3d = getFilterContext(hasImplThread);
393 GrContext* grContext = getFilterGrContext(hasImplThread);
395 if (!context3d || !grContext)
396 return SkBitmap();
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.
411 SkBitmap source;
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.
417 GrTextureDesc desc;
418 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
419 desc.fSampleCnt = 0;
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.
431 SkPaint paint;
432 paint.setImageFilter(filter);
433 canvas.clear(0x0);
434 canvas.drawSprite(source, 0, 0, &paint);
435 canvas.flush();
436 context3d->flush();
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())
518 return;
520 const RenderPass* renderPass = frame.renderPassesById->get(quad->render_pass_id);
521 DCHECK(renderPass);
522 if (!renderPass)
523 return;
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())
531 return;
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());
543 } else {
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);
556 DCHECK(!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());
562 if (useAA) {
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());
580 } else
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();
628 } else {
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,
645 0.0f, 0.0f,
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));
650 } else {
651 NOTREACHED();
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) {
668 float edge[24];
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);
676 DCHECK(!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())
685 m_context->flush();
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 {
703 unsigned program;
704 unsigned samplerLocation;
705 unsigned vertexTexTransformLocation;
706 unsigned fragmentTexTransformLocation;
707 unsigned edgeLocation;
708 unsigned matrixLocation;
709 unsigned alphaLocation;
710 unsigned pointLocation;
713 template<class T>
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())
781 return;
783 bool clipped = false;
784 gfx::QuadF deviceLayerQuad = MathUtil::mapQuad(deviceTransform, gfx::QuadF(quad->visibleContentRect()), clipped);
785 DCHECK(!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);
793 else
794 tileUniformLocation(tileProgramAA(), uniforms);
795 } else {
796 if (quad->ShouldDrawWithBlending()) {
797 if (quad->swizzle_contents)
798 tileUniformLocation(tileProgramSwizzle(), uniforms);
799 else
800 tileUniformLocation(tileProgram(), uniforms);
801 } else {
802 if (quad->swizzle_contents)
803 tileUniformLocation(tileProgramSwizzleOpaque(), uniforms);
804 else
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();
816 if (useAA) {
817 LayerQuad deviceLayerBounds = LayerQuad(gfx::QuadF(deviceLayerQuad.BoundingBox()));
818 deviceLayerBounds.inflateAntiAliasingDistance();
820 LayerQuad deviceLayerEdges = LayerQuad(deviceLayerQuad);
821 deviceLayerEdges.inflateAntiAliasingDistance();
823 float edge[24];
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);
838 DCHECK(!clipped);
839 bottomLeft = MathUtil::mapPoint(deviceTransform, bottomLeft, clipped);
840 DCHECK(!clipped);
841 topLeft = MathUtil::mapPoint(deviceTransform, topLeft, clipped);
842 DCHECK(!clipped);
843 topRight = MathUtil::mapPoint(deviceTransform, topRight, clipped);
844 DCHECK(!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);
864 topEdge.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.
876 } else {
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
933 float yuv2RGB[9] = {
934 1.164f, 1.164f, 1.164f,
935 0.f, -.391f, 2.018f,
936 1.596f, -.813f, 0.f,
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] = {
947 -0.0625f,
948 -0.5f,
949 -0.5f,
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();
990 int programId;
991 int samplerLocation;
992 int matrixLocation;
993 int 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)
1012 return;
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())));
1048 // Draw the quads!
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));
1055 // Clear the cache.
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;
1066 if (quad->flipped)
1067 binding.set(textureProgramFlip(), context());
1068 else
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;
1107 Float16 m;
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;
1115 if (quad->flipped)
1116 binding.set(textureProgramFlip(), context());
1117 else
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));
1155 else
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
1192 return true;
1195 void GLRenderer::ensureScissorTestEnabled()
1197 if (m_isScissorEnabled)
1198 return;
1200 flushTextureQuadCache();
1201 GLC(m_context, m_context->enable(GL_SCISSOR_TEST));
1202 m_isScissorEnabled = true;
1205 void GLRenderer::ensureScissorTestDisabled()
1207 if (!m_isScissorEnabled)
1208 return;
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)
1223 return;
1225 float point[8];
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)
1246 return;
1248 if (enabled)
1249 GLC(m_context, m_context->enable(GL_BLEND));
1250 else
1251 GLC(m_context, m_context->disable(GL_BLEND));
1252 m_blendShadow = enabled;
1255 void GLRenderer::setUseProgram(unsigned program)
1257 if (program == m_programShadow)
1258 return;
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()
1296 DCHECK(m_visible);
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());
1307 } else {
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();
1315 return true;
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);
1337 else
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();
1360 NOTREACHED();
1361 return 0;
1364 void GLRenderer::enforceMemoryPolicy()
1366 if (!m_visible) {
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)
1378 return;
1380 if (!m_capabilities.usingDiscardBackbuffer)
1381 return;
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)
1393 return;
1395 if (!m_capabilities.usingDiscardBackbuffer)
1396 return;
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());
1413 if (!pixels)
1414 return;
1416 makeContextCurrent();
1418 bool doWorkaround = needsIOSurfaceReadbackWorkaround();
1420 GLuint temporaryTexture = 0;
1421 GLuint temporaryFBO = 0;
1423 if (doWorkaround) {
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) {
1454 // Flip Y axis.
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)];
1465 if (doWorkaround) {
1466 // Clean up.
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))
1481 return false;
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));
1487 return true;
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());
1519 return true;
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)
1529 return;
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());
1563 return true;
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();
1756 if (m_tileProgram)
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);
1806 } // namespace cc