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