OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/gl_renderer.h" | |
6 | |
7 #include <set> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/debug/trace_event.h" | |
12 #include "base/logging.h" | |
13 #include "base/string_util.h" | |
14 #include "base/strings/string_split.h" | |
15 #include "build/build_config.h" | |
16 #include "cc/base/math_util.h" | |
17 #include "cc/compositor_frame.h" | |
18 #include "cc/compositor_frame_metadata.h" | |
19 #include "cc/context_provider.h" | |
20 #include "cc/damage_tracker.h" | |
21 #include "cc/geometry_binding.h" | |
22 #include "cc/gl_frame_data.h" | |
23 #include "cc/layer_quad.h" | |
24 #include "cc/output_surface.h" | |
25 #include "cc/priority_calculator.h" | |
26 #include "cc/proxy.h" | |
27 #include "cc/render_pass.h" | |
28 #include "cc/render_surface_filters.h" | |
29 #include "cc/scoped_resource.h" | |
30 #include "cc/single_thread_proxy.h" | |
31 #include "cc/stream_video_draw_quad.h" | |
32 #include "cc/texture_draw_quad.h" | |
33 #include "cc/video_layer_impl.h" | |
34 #include "gpu/GLES2/gl2extchromium.h" | |
35 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3
D.h" | |
36 #include "third_party/khronos/GLES2/gl2.h" | |
37 #include "third_party/khronos/GLES2/gl2ext.h" | |
38 #include "third_party/skia/include/core/SkBitmap.h" | |
39 #include "third_party/skia/include/core/SkColor.h" | |
40 #include "third_party/skia/include/gpu/GrContext.h" | |
41 #include "third_party/skia/include/gpu/GrTexture.h" | |
42 #include "third_party/skia/include/gpu/SkGpuDevice.h" | |
43 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h" | |
44 #include "ui/gfx/quad_f.h" | |
45 #include "ui/gfx/rect_conversions.h" | |
46 | |
47 using WebKit::WebGraphicsContext3D; | |
48 using WebKit::WebGraphicsMemoryAllocation; | |
49 | |
50 namespace cc { | |
51 | |
52 namespace { | |
53 | |
54 // TODO(epenner): This should probably be moved to output surface. | |
55 // | |
56 // This implements a simple fence based on client side swaps. | |
57 // This is to isolate the ResourceProvider from 'frames' which | |
58 // it shouldn't need to care about, while still allowing us to | |
59 // enforce good texture recycling behavior strictly throughout | |
60 // the compositor (don't recycle a texture while it's in use). | |
61 class SimpleSwapFence : public ResourceProvider::Fence { | |
62 public: | |
63 SimpleSwapFence() : has_passed_(false) {} | |
64 virtual bool HasPassed() OVERRIDE { return has_passed_; } | |
65 void SetHasPassed() { has_passed_ = true; } | |
66 private: | |
67 virtual ~SimpleSwapFence() {} | |
68 bool has_passed_; | |
69 }; | |
70 | |
71 bool NeedsIOSurfaceReadbackWorkaround() { | |
72 #if defined(OS_MACOSX) | |
73 return true; | |
74 #else | |
75 return false; | |
76 #endif | |
77 } | |
78 | |
79 } // anonymous namespace | |
80 | |
81 scoped_ptr<GLRenderer> GLRenderer::Create(RendererClient* client, | |
82 OutputSurface* output_surface, | |
83 ResourceProvider* resource_provider) { | |
84 scoped_ptr<GLRenderer> renderer( | |
85 new GLRenderer(client, output_surface, resource_provider)); | |
86 if (!renderer->Initialize()) | |
87 return scoped_ptr<GLRenderer>(); | |
88 | |
89 return renderer.Pass(); | |
90 } | |
91 | |
92 GLRenderer::GLRenderer(RendererClient* client, | |
93 OutputSurface* output_surface, | |
94 ResourceProvider* resource_provider) | |
95 : DirectRenderer(client, resource_provider), | |
96 offscreen_framebuffer_id_(0), | |
97 shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)), | |
98 output_surface_(output_surface), | |
99 context_(output_surface->context3d()), | |
100 is_viewport_changed_(false), | |
101 is_backbuffer_discarded_(false), | |
102 discard_backbuffer_when_not_visible_(false), | |
103 is_using_bind_uniform_(false), | |
104 visible_(true), | |
105 is_scissor_enabled_(false) { | |
106 DCHECK(context_); | |
107 } | |
108 | |
109 bool GLRenderer::Initialize() { | |
110 if (!context_->makeContextCurrent()) | |
111 return false; | |
112 | |
113 context_->setContextLostCallback(this); | |
114 context_->pushGroupMarkerEXT("CompositorContext"); | |
115 | |
116 std::string extensions_string = | |
117 UTF16ToASCII(context_->getString(GL_EXTENSIONS)); | |
118 std::vector<std::string> extensions_list; | |
119 base::SplitString(extensions_string, ' ', &extensions_list); | |
120 std::set<std::string> extensions(extensions_list.begin(), | |
121 extensions_list.end()); | |
122 | |
123 if (Settings().acceleratePainting && | |
124 extensions.count("GL_EXT_texture_format_BGRA8888") && | |
125 extensions.count("GL_EXT_read_format_bgra")) | |
126 capabilities_.using_accelerated_painting = true; | |
127 else | |
128 capabilities_.using_accelerated_painting = false; | |
129 | |
130 capabilities_.using_partial_swap = | |
131 Settings().partialSwapEnabled && | |
132 extensions.count("GL_CHROMIUM_post_sub_buffer"); | |
133 | |
134 // Use the swapBuffers callback only with the threaded proxy. | |
135 if (client_->HasImplThread()) | |
136 capabilities_.using_swap_complete_callback = | |
137 extensions.count("GL_CHROMIUM_swapbuffers_complete_callback"); | |
138 if (capabilities_.using_swap_complete_callback) | |
139 context_->setSwapBuffersCompleteCallbackCHROMIUM(this); | |
140 | |
141 capabilities_.using_set_visibility = | |
142 extensions.count("GL_CHROMIUM_set_visibility"); | |
143 | |
144 if (extensions.count("GL_CHROMIUM_iosurface")) | |
145 DCHECK(extensions.count("GL_ARB_texture_rectangle")); | |
146 | |
147 capabilities_.using_gpu_memory_manager = | |
148 extensions.count("GL_CHROMIUM_gpu_memory_manager") && | |
149 Settings().useMemoryManagement; | |
150 if (capabilities_.using_gpu_memory_manager) | |
151 context_->setMemoryAllocationChangedCallbackCHROMIUM(this); | |
152 | |
153 capabilities_.using_egl_image = extensions.count("GL_OES_EGL_image_external"); | |
154 | |
155 capabilities_.max_texture_size = resource_provider_->max_texture_size(); | |
156 capabilities_.best_texture_format = resource_provider_->best_texture_format(); | |
157 | |
158 // The updater can access textures while the GLRenderer is using them. | |
159 capabilities_.allow_partial_texture_updates = true; | |
160 | |
161 // Check for texture fast paths. Currently we always use MO8 textures, | |
162 // so we only need to avoid POT textures if we have an NPOT fast-path. | |
163 capabilities_.avoid_pow2_textures = | |
164 extensions.count("GL_CHROMIUM_fast_NPOT_MO8_textures"); | |
165 | |
166 capabilities_.using_offscreen_context3d = true; | |
167 | |
168 is_using_bind_uniform_ = | |
169 extensions.count("GL_CHROMIUM_bind_uniform_location"); | |
170 | |
171 // Make sure scissoring starts as disabled. | |
172 GLC(context_, context_->disable(GL_SCISSOR_TEST)); | |
173 DCHECK(!is_scissor_enabled_); | |
174 | |
175 if (!InitializeSharedObjects()) | |
176 return false; | |
177 | |
178 // Make sure the viewport and context gets initialized, even if it is to zero. | |
179 ViewportChanged(); | |
180 return true; | |
181 } | |
182 | |
183 GLRenderer::~GLRenderer() { | |
184 context_->setSwapBuffersCompleteCallbackCHROMIUM(NULL); | |
185 context_->setMemoryAllocationChangedCallbackCHROMIUM(NULL); | |
186 context_->setContextLostCallback(NULL); | |
187 CleanupSharedObjects(); | |
188 } | |
189 | |
190 const RendererCapabilities& GLRenderer::Capabilities() const { | |
191 return capabilities_; | |
192 } | |
193 | |
194 WebGraphicsContext3D* GLRenderer::Context() { return context_; } | |
195 | |
196 void GLRenderer::DebugGLCall(WebGraphicsContext3D* context, | |
197 const char* command, | |
198 const char* file, | |
199 int line) { | |
200 unsigned long error = context->getError(); | |
201 if (error != GL_NO_ERROR) | |
202 LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line | |
203 << "\n\tcommand: " << command << ", error " | |
204 << static_cast<int>(error) << "\n"; | |
205 } | |
206 | |
207 void GLRenderer::SetVisible(bool visible) { | |
208 if (visible_ == visible) | |
209 return; | |
210 visible_ = visible; | |
211 | |
212 EnforceMemoryPolicy(); | |
213 | |
214 // TODO: Replace setVisibilityCHROMIUM with an extension to explicitly manage | |
215 // front/backbuffers | |
216 // crbug.com/116049 | |
217 if (capabilities_.using_set_visibility) | |
218 context_->setVisibilityCHROMIUM(visible); | |
219 } | |
220 | |
221 void GLRenderer::SendManagedMemoryStats(size_t bytes_visible, | |
222 size_t bytes_visible_and_nearby, | |
223 size_t bytes_allocated) { | |
224 WebKit::WebGraphicsManagedMemoryStats stats; | |
225 stats.bytesVisible = bytes_visible; | |
226 stats.bytesVisibleAndNearby = bytes_visible_and_nearby; | |
227 stats.bytesAllocated = bytes_allocated; | |
228 stats.backbufferRequested = !is_backbuffer_discarded_; | |
229 context_->sendManagedMemoryStatsCHROMIUM(&stats); | |
230 } | |
231 | |
232 void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); } | |
233 | |
234 void GLRenderer::ViewportChanged() { is_viewport_changed_ = true; } | |
235 | |
236 void GLRenderer::ClearFramebuffer(DrawingFrame& frame) { | |
237 // On DEBUG builds, opaque render passes are cleared to blue to easily see | |
238 // regions that were not drawn on the screen. | |
239 if (frame.current_render_pass->has_transparent_background) | |
240 GLC(context_, context_->clearColor(0, 0, 0, 0)); | |
241 else | |
242 GLC(context_, context_->clearColor(0, 0, 1, 1)); | |
243 | |
244 #ifdef NDEBUG | |
245 if (frame.current_render_pass->has_transparent_background) | |
246 #endif | |
247 context_->clear(GL_COLOR_BUFFER_BIT); | |
248 } | |
249 | |
250 void GLRenderer::BeginDrawingFrame(DrawingFrame& frame) { | |
251 // FIXME: Remove this once backbuffer is automatically recreated on first use | |
252 EnsureBackbuffer(); | |
253 | |
254 if (ViewportSize().IsEmpty()) | |
255 return; | |
256 | |
257 TRACE_EVENT0("cc", "GLRenderer::drawLayers"); | |
258 if (is_viewport_changed_) { | |
259 // Only reshape when we know we are going to draw. Otherwise, the reshape | |
260 // can leave the window at the wrong size if we never draw and the proper | |
261 // viewport size is never set. | |
262 is_viewport_changed_ = false; | |
263 output_surface_->Reshape(gfx::Size(ViewportWidth(), ViewportHeight())); | |
264 } | |
265 | |
266 MakeContextCurrent(); | |
267 // Bind the common vertex attributes used for drawing all the layers. | |
268 shared_geometry_->PrepareForDraw(); | |
269 | |
270 GLC(context_, context_->disable(GL_DEPTH_TEST)); | |
271 GLC(context_, context_->disable(GL_CULL_FACE)); | |
272 GLC(context_, context_->colorMask(true, true, true, true)); | |
273 GLC(context_, context_->enable(GL_BLEND)); | |
274 blend_shadow_ = true; | |
275 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
276 GLC(Context(), Context()->activeTexture(GL_TEXTURE0)); | |
277 program_shadow_ = 0; | |
278 } | |
279 | |
280 void GLRenderer::DoNoOp() { | |
281 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0)); | |
282 GLC(context_, context_->flush()); | |
283 } | |
284 | |
285 void GLRenderer::DoDrawQuad(DrawingFrame& frame, const DrawQuad* quad) { | |
286 DCHECK(quad->rect.Contains(quad->visible_rect)); | |
287 if (quad->material != DrawQuad::TEXTURE_CONTENT) { | |
288 FlushTextureQuadCache(); | |
289 } | |
290 | |
291 switch (quad->material) { | |
292 case DrawQuad::INVALID: | |
293 NOTREACHED(); | |
294 break; | |
295 case DrawQuad::CHECKERBOARD: | |
296 DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad)); | |
297 break; | |
298 case DrawQuad::DEBUG_BORDER: | |
299 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad)); | |
300 break; | |
301 case DrawQuad::IO_SURFACE_CONTENT: | |
302 DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad)); | |
303 break; | |
304 case DrawQuad::RENDER_PASS: | |
305 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad)); | |
306 break; | |
307 case DrawQuad::SOLID_COLOR: | |
308 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad)); | |
309 break; | |
310 case DrawQuad::STREAM_VIDEO_CONTENT: | |
311 DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad)); | |
312 break; | |
313 case DrawQuad::TEXTURE_CONTENT: | |
314 EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad)); | |
315 break; | |
316 case DrawQuad::TILED_CONTENT: | |
317 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad)); | |
318 break; | |
319 case DrawQuad::YUV_VIDEO_CONTENT: | |
320 DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad)); | |
321 break; | |
322 } | |
323 } | |
324 | |
325 void GLRenderer::DrawCheckerboardQuad(const DrawingFrame& frame, | |
326 const CheckerboardDrawQuad* quad) { | |
327 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
328 | |
329 const TileCheckerboardProgram* program = GetTileCheckerboardProgram(); | |
330 DCHECK(program && (program->initialized() || IsContextLost())); | |
331 SetUseProgram(program->program()); | |
332 | |
333 SkColor color = quad->color; | |
334 GLC(Context(), | |
335 Context()->uniform4f(program->fragment_shader().colorLocation(), | |
336 SkColorGetR(color) * (1.0f / 255.0f), | |
337 SkColorGetG(color) * (1.0f / 255.0f), | |
338 SkColorGetB(color) * (1.0f / 255.0f), | |
339 1)); | |
340 | |
341 const int checkerboard_width = 16; | |
342 float frequency = 1.0f / checkerboard_width; | |
343 | |
344 gfx::Rect tile_rect = quad->rect; | |
345 float tex_offset_x = tile_rect.x() % checkerboard_width; | |
346 float tex_offset_y = tile_rect.y() % checkerboard_width; | |
347 float tex_scale_x = tile_rect.width(); | |
348 float tex_scale_y = tile_rect.height(); | |
349 GLC(Context(), | |
350 Context()->uniform4f(program->fragment_shader().texTransformLocation(), | |
351 tex_offset_x, | |
352 tex_offset_y, | |
353 tex_scale_x, | |
354 tex_scale_y)); | |
355 | |
356 GLC(Context(), | |
357 Context()->uniform1f(program->fragment_shader().frequencyLocation(), | |
358 frequency)); | |
359 | |
360 SetShaderOpacity(quad->opacity(), program->fragment_shader().alphaLocation()); | |
361 DrawQuadGeometry(frame, | |
362 quad->quadTransform(), | |
363 quad->rect, | |
364 program->vertex_shader().matrixLocation()); | |
365 } | |
366 | |
367 void GLRenderer::DrawDebugBorderQuad(const DrawingFrame& frame, | |
368 const DebugBorderDrawQuad* quad) { | |
369 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
370 | |
371 static float gl_matrix[16]; | |
372 const DebugBorderProgram* program = GetDebugBorderProgram(); | |
373 DCHECK(program && (program->initialized() || IsContextLost())); | |
374 SetUseProgram(program->program()); | |
375 | |
376 // Use the full quad_rect for debug quads to not move the edges based on | |
377 // partial swaps. | |
378 gfx::Rect layer_rect = quad->rect; | |
379 gfx::Transform render_matrix = quad->quadTransform(); | |
380 render_matrix.Translate(0.5f * layer_rect.width() + layer_rect.x(), | |
381 0.5f * layer_rect.height() + layer_rect.y()); | |
382 render_matrix.Scale(layer_rect.width(), layer_rect.height()); | |
383 GLRenderer::ToGLMatrix(&gl_matrix[0], | |
384 frame.projection_matrix * render_matrix); | |
385 GLC(Context(), | |
386 Context()->uniformMatrix4fv( | |
387 program->vertex_shader().matrixLocation(), 1, false, &gl_matrix[0])); | |
388 | |
389 SkColor color = quad->color; | |
390 float alpha = SkColorGetA(color) * (1.0f / 255.0f); | |
391 | |
392 GLC(Context(), | |
393 Context()->uniform4f(program->fragment_shader().colorLocation(), | |
394 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, | |
395 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, | |
396 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, | |
397 alpha)); | |
398 | |
399 GLC(Context(), Context()->lineWidth(quad->width)); | |
400 | |
401 // The indices for the line are stored in the same array as the triangle | |
402 // indices. | |
403 GLC(Context(), | |
404 Context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0)); | |
405 } | |
406 | |
407 static inline SkBitmap ApplyFilters(GLRenderer* renderer, | |
408 const WebKit::WebFilterOperations& filters, | |
409 ScopedResource* source_texture_resource) { | |
410 if (filters.isEmpty()) | |
411 return SkBitmap(); | |
412 | |
413 ContextProvider* offscreen_contexts = | |
414 renderer->resource_provider()->offscreen_context_provider(); | |
415 if (!offscreen_contexts || !offscreen_contexts->GrContext()) | |
416 return SkBitmap(); | |
417 | |
418 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(), | |
419 source_texture_resource->id()); | |
420 | |
421 // Flush the compositor context to ensure that textures there are available | |
422 // in the shared context. Do this after locking/creating the compositor | |
423 // texture. | |
424 renderer->resource_provider()->Flush(); | |
425 | |
426 // Make sure skia uses the correct GL context. | |
427 offscreen_contexts->Context3d()->makeContextCurrent(); | |
428 | |
429 SkBitmap source = | |
430 RenderSurfaceFilters::Apply(filters, | |
431 lock.texture_id(), | |
432 source_texture_resource->size(), | |
433 offscreen_contexts->GrContext()); | |
434 | |
435 // Flush skia context so that all the rendered stuff appears on the | |
436 // texture. | |
437 offscreen_contexts->GrContext()->flush(); | |
438 | |
439 // Flush the GL context so rendering results from this context are | |
440 // visible in the compositor's context. | |
441 offscreen_contexts->Context3d()->flush(); | |
442 | |
443 // Use the compositor's GL context again. | |
444 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent(); | |
445 return source; | |
446 } | |
447 | |
448 static SkBitmap ApplyImageFilter(GLRenderer* renderer, | |
449 SkImageFilter* filter, | |
450 ScopedResource* source_texture_resource) { | |
451 if (!filter) | |
452 return SkBitmap(); | |
453 | |
454 ContextProvider* offscreen_contexts = | |
455 renderer->resource_provider()->offscreen_context_provider(); | |
456 if (!offscreen_contexts || !offscreen_contexts->GrContext()) | |
457 return SkBitmap(); | |
458 | |
459 ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(), | |
460 source_texture_resource->id()); | |
461 | |
462 // Flush the compositor context to ensure that textures there are available | |
463 // in the shared context. Do this after locking/creating the compositor | |
464 // texture. | |
465 renderer->resource_provider()->Flush(); | |
466 | |
467 // Make sure skia uses the correct GL context. | |
468 offscreen_contexts->Context3d()->makeContextCurrent(); | |
469 | |
470 // Wrap the source texture in a Ganesh platform texture. | |
471 GrBackendTextureDesc backend_texture_description; | |
472 backend_texture_description.fWidth = source_texture_resource->size().width(); | |
473 backend_texture_description.fHeight = | |
474 source_texture_resource->size().height(); | |
475 backend_texture_description.fConfig = kSkia8888_GrPixelConfig; | |
476 backend_texture_description.fTextureHandle = lock.texture_id(); | |
477 backend_texture_description.fOrigin = kTopLeft_GrSurfaceOrigin; | |
478 skia::RefPtr<GrTexture> texture = | |
479 skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture( | |
480 backend_texture_description)); | |
481 | |
482 // Place the platform texture inside an SkBitmap. | |
483 SkBitmap source; | |
484 source.setConfig(SkBitmap::kARGB_8888_Config, | |
485 source_texture_resource->size().width(), | |
486 source_texture_resource->size().height()); | |
487 skia::RefPtr<SkGrPixelRef> pixel_ref = | |
488 skia::AdoptRef(new SkGrPixelRef(texture.get())); | |
489 source.setPixelRef(pixel_ref.get()); | |
490 | |
491 // Create a scratch texture for backing store. | |
492 GrTextureDesc desc; | |
493 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | |
494 desc.fSampleCnt = 0; | |
495 desc.fWidth = source.width(); | |
496 desc.fHeight = source.height(); | |
497 desc.fConfig = kSkia8888_GrPixelConfig; | |
498 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
499 GrAutoScratchTexture scratchTexture( | |
500 offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch); | |
501 skia::RefPtr<GrTexture> backing_store = | |
502 skia::AdoptRef(scratchTexture.detach()); | |
503 | |
504 // Create a device and canvas using that backing store. | |
505 SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get()); | |
506 SkCanvas canvas(&device); | |
507 | |
508 // Draw the source bitmap through the filter to the canvas. | |
509 SkPaint paint; | |
510 paint.setImageFilter(filter); | |
511 canvas.clear(SK_ColorTRANSPARENT); | |
512 canvas.drawSprite(source, 0, 0, &paint); | |
513 | |
514 // Flush skia context so that all the rendered stuff appears on the | |
515 // texture. | |
516 offscreen_contexts->GrContext()->flush(); | |
517 | |
518 // Flush the GL context so rendering results from this context are | |
519 // visible in the compositor's context. | |
520 offscreen_contexts->Context3d()->flush(); | |
521 | |
522 // Use the compositor's GL context again. | |
523 renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent(); | |
524 | |
525 return device.accessBitmap(false); | |
526 } | |
527 | |
528 scoped_ptr<ScopedResource> GLRenderer::DrawBackgroundFilters( | |
529 DrawingFrame& frame, | |
530 const RenderPassDrawQuad* quad, | |
531 const gfx::Transform& contents_device_transform, | |
532 const gfx::Transform& contents_device_transform_inverse) { | |
533 // This method draws a background filter, which applies a filter to any pixels | |
534 // behind the quad and seen through its background. The algorithm works as | |
535 // follows: | |
536 // 1. Compute a bounding box around the pixels that will be visible through | |
537 // the quad. | |
538 // 2. Read the pixels in the bounding box into a buffer R. | |
539 // 3. Apply the background filter to R, so that it is applied in the pixels' | |
540 // coordinate space. | |
541 // 4. Apply the quad's inverse transform to map the pixels in R into the | |
542 // quad's content space. This implicitly clips R by the content bounds of the | |
543 // quad since the destination texture has bounds matching the quad's content. | |
544 // 5. Draw the background texture for the contents using the same transform as | |
545 // used to draw the contents itself. This is done without blending to replace | |
546 // the current background pixels with the new filtered background. | |
547 // 6. Draw the contents of the quad over drop of the new background with | |
548 // blending, as per usual. The filtered background pixels will show through | |
549 // any non-opaque pixels in this draws. | |
550 // | |
551 // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5. | |
552 | |
553 // FIXME: When this algorithm changes, update | |
554 // LayerTreeHost::prioritizeTextures() accordingly. | |
555 | |
556 const WebKit::WebFilterOperations& filters = quad->background_filters; | |
557 if (filters.isEmpty()) | |
558 return scoped_ptr<ScopedResource>(); | |
559 | |
560 // FIXME: We only allow background filters on an opaque render surface because | |
561 // other surfaces may contain translucent pixels, and the contents behind | |
562 // those translucent pixels wouldn't have the filter applied. | |
563 if (frame.current_render_pass->has_transparent_background) | |
564 return scoped_ptr<ScopedResource>(); | |
565 DCHECK(!frame.current_texture); | |
566 | |
567 // FIXME: Do a single readback for both the surface and replica and cache the | |
568 // filtered results (once filter textures are not reused). | |
569 gfx::Rect device_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( | |
570 contents_device_transform, SharedGeometryQuad().BoundingBox())); | |
571 | |
572 int top, right, bottom, left; | |
573 filters.getOutsets(top, right, bottom, left); | |
574 device_rect.Inset(-left, -top, -right, -bottom); | |
575 | |
576 device_rect.Intersect(frame.current_render_pass->output_rect); | |
577 | |
578 scoped_ptr<ScopedResource> device_background_texture = | |
579 ScopedResource::create(resource_provider_); | |
580 if (!GetFramebufferTexture(device_background_texture.get(), device_rect)) | |
581 return scoped_ptr<ScopedResource>(); | |
582 | |
583 SkBitmap filtered_device_background = | |
584 ApplyFilters(this, filters, device_background_texture.get()); | |
585 if (!filtered_device_background.getTexture()) | |
586 return scoped_ptr<ScopedResource>(); | |
587 | |
588 GrTexture* texture = | |
589 reinterpret_cast<GrTexture*>(filtered_device_background.getTexture()); | |
590 int filtered_device_background_texture_id = texture->getTextureHandle(); | |
591 | |
592 scoped_ptr<ScopedResource> background_texture = | |
593 ScopedResource::create(resource_provider_); | |
594 if (!background_texture->Allocate(quad->rect.size(), | |
595 GL_RGBA, | |
596 ResourceProvider::TextureUsageFramebuffer)) | |
597 return scoped_ptr<ScopedResource>(); | |
598 | |
599 const RenderPass* target_render_pass = frame.current_render_pass; | |
600 bool using_background_texture = | |
601 UseScopedTexture(frame, background_texture.get(), quad->rect); | |
602 | |
603 if (using_background_texture) { | |
604 // Copy the readback pixels from device to the background texture for the | |
605 // surface. | |
606 gfx::Transform device_to_framebuffer_transform; | |
607 device_to_framebuffer_transform.Translate( | |
608 quad->rect.width() * 0.5f + quad->rect.x(), | |
609 quad->rect.height() * 0.5f + quad->rect.y()); | |
610 device_to_framebuffer_transform.Scale(quad->rect.width(), | |
611 quad->rect.height()); | |
612 device_to_framebuffer_transform.PreconcatTransform( | |
613 contents_device_transform_inverse); | |
614 | |
615 #ifndef NDEBUG | |
616 GLC(Context(), Context()->clearColor(0, 0, 1, 1)); | |
617 Context()->clear(GL_COLOR_BUFFER_BIT); | |
618 #endif | |
619 | |
620 CopyTextureToFramebuffer(frame, | |
621 filtered_device_background_texture_id, | |
622 device_rect, | |
623 device_to_framebuffer_transform); | |
624 } | |
625 | |
626 UseRenderPass(frame, target_render_pass); | |
627 | |
628 if (!using_background_texture) | |
629 return scoped_ptr<ScopedResource>(); | |
630 return background_texture.Pass(); | |
631 } | |
632 | |
633 void GLRenderer::DrawRenderPassQuad(DrawingFrame& frame, | |
634 const RenderPassDrawQuad* quad) { | |
635 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
636 | |
637 CachedResource* contents_texture = | |
638 render_pass_textures_.get(quad->render_pass_id); | |
639 if (!contents_texture || !contents_texture->id()) | |
640 return; | |
641 | |
642 gfx::Transform quad_rect_matrix; | |
643 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); | |
644 gfx::Transform contents_device_transform = | |
645 frame.window_matrix * frame.projection_matrix * quad_rect_matrix; | |
646 contents_device_transform.FlattenTo2d(); | |
647 | |
648 // Can only draw surface if device matrix is invertible. | |
649 gfx::Transform contents_device_transform_inverse( | |
650 gfx::Transform::kSkipInitialization); | |
651 if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) | |
652 return; | |
653 | |
654 scoped_ptr<ScopedResource> background_texture = | |
655 DrawBackgroundFilters(frame, | |
656 quad, | |
657 contents_device_transform, | |
658 contents_device_transform_inverse); | |
659 | |
660 // FIXME: Cache this value so that we don't have to do it for both the surface | |
661 // and its replica. Apply filters to the contents texture. | |
662 SkBitmap filter_bitmap; | |
663 if (quad->filter) { | |
664 filter_bitmap = | |
665 ApplyImageFilter(this, quad->filter.get(), contents_texture); | |
666 } else { | |
667 filter_bitmap = ApplyFilters(this, quad->filters, contents_texture); | |
668 } | |
669 | |
670 // Draw the background texture if there is one. | |
671 if (background_texture) { | |
672 DCHECK(background_texture->size() == quad->rect.size()); | |
673 ResourceProvider::ScopedReadLockGL lock(resource_provider_, | |
674 background_texture->id()); | |
675 CopyTextureToFramebuffer( | |
676 frame, lock.texture_id(), quad->rect, quad->quadTransform()); | |
677 } | |
678 | |
679 bool clipped = false; | |
680 gfx::QuadF device_quad = MathUtil::MapQuad( | |
681 contents_device_transform, SharedGeometryQuad(), &clipped); | |
682 DCHECK(!clipped); | |
683 LayerQuad deviceLayerBounds(gfx::QuadF(device_quad.BoundingBox())); | |
684 LayerQuad device_layer_edges(device_quad); | |
685 | |
686 // Use anti-aliasing programs only when necessary. | |
687 bool use_aa = (!device_quad.IsRectilinear() || | |
688 !device_quad.BoundingBox().IsExpressibleAsRect()); | |
689 if (use_aa) { | |
690 deviceLayerBounds.InflateAntiAliasingDistance(); | |
691 device_layer_edges.InflateAntiAliasingDistance(); | |
692 } | |
693 | |
694 scoped_ptr<ResourceProvider::ScopedReadLockGL> mask_resource_lock; | |
695 unsigned mask_texture_id = 0; | |
696 if (quad->mask_resource_id) { | |
697 mask_resource_lock.reset(new ResourceProvider::ScopedReadLockGL( | |
698 resource_provider_, quad->mask_resource_id)); | |
699 mask_texture_id = mask_resource_lock->texture_id(); | |
700 } | |
701 | |
702 // FIXME: use the background_texture and blend the background in with this | |
703 // draw instead of having a separate copy of the background texture. | |
704 | |
705 scoped_ptr<ResourceProvider::ScopedReadLockGL> contents_resource_lock; | |
706 if (filter_bitmap.getTexture()) { | |
707 GrTexture* texture = | |
708 reinterpret_cast<GrTexture*>(filter_bitmap.getTexture()); | |
709 Context()->bindTexture(GL_TEXTURE_2D, texture->getTextureHandle()); | |
710 } else | |
711 contents_resource_lock = make_scoped_ptr( | |
712 new ResourceProvider::ScopedSamplerGL(resource_provider_, | |
713 contents_texture->id(), | |
714 GL_TEXTURE_2D, | |
715 GL_LINEAR)); | |
716 | |
717 int shader_quad_location = -1; | |
718 int shader_edge_location = -1; | |
719 int shader_mask_sampler_location = -1; | |
720 int shader_mask_tex_coord_scale_location = -1; | |
721 int shader_mask_tex_coord_offset_location = -1; | |
722 int shader_matrix_location = -1; | |
723 int shader_alpha_location = -1; | |
724 int shader_tex_transform_location = -1; | |
725 int shader_tex_scale_location = -1; | |
726 | |
727 if (use_aa && mask_texture_id) { | |
728 const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(); | |
729 SetUseProgram(program->program()); | |
730 GLC(Context(), | |
731 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
732 | |
733 shader_quad_location = program->vertex_shader().pointLocation(); | |
734 shader_edge_location = program->fragment_shader().edgeLocation(); | |
735 shader_mask_sampler_location = | |
736 program->fragment_shader().maskSamplerLocation(); | |
737 shader_mask_tex_coord_scale_location = | |
738 program->fragment_shader().maskTexCoordScaleLocation(); | |
739 shader_mask_tex_coord_offset_location = | |
740 program->fragment_shader().maskTexCoordOffsetLocation(); | |
741 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
742 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
743 shader_tex_scale_location = program->vertex_shader().texScaleLocation(); | |
744 } else if (!use_aa && mask_texture_id) { | |
745 const RenderPassMaskProgram* program = GetRenderPassMaskProgram(); | |
746 SetUseProgram(program->program()); | |
747 GLC(Context(), | |
748 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
749 | |
750 shader_mask_sampler_location = | |
751 program->fragment_shader().maskSamplerLocation(); | |
752 shader_mask_tex_coord_scale_location = | |
753 program->fragment_shader().maskTexCoordScaleLocation(); | |
754 shader_mask_tex_coord_offset_location = | |
755 program->fragment_shader().maskTexCoordOffsetLocation(); | |
756 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
757 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
758 shader_tex_transform_location = | |
759 program->vertex_shader().texTransformLocation(); | |
760 } else if (use_aa && !mask_texture_id) { | |
761 const RenderPassProgramAA* program = GetRenderPassProgramAA(); | |
762 SetUseProgram(program->program()); | |
763 GLC(Context(), | |
764 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
765 | |
766 shader_quad_location = program->vertex_shader().pointLocation(); | |
767 shader_edge_location = program->fragment_shader().edgeLocation(); | |
768 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
769 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
770 shader_tex_scale_location = program->vertex_shader().texScaleLocation(); | |
771 } else { | |
772 const RenderPassProgram* program = GetRenderPassProgram(); | |
773 SetUseProgram(program->program()); | |
774 GLC(Context(), | |
775 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
776 | |
777 shader_matrix_location = program->vertex_shader().matrixLocation(); | |
778 shader_alpha_location = program->fragment_shader().alphaLocation(); | |
779 shader_tex_transform_location = | |
780 program->vertex_shader().texTransformLocation(); | |
781 } | |
782 | |
783 float tex_scale_x = | |
784 quad->rect.width() / static_cast<float>(contents_texture->size().width()); | |
785 float tex_scale_y = quad->rect.height() / | |
786 static_cast<float>(contents_texture->size().height()); | |
787 DCHECK_LE(tex_scale_x, 1.0f); | |
788 DCHECK_LE(tex_scale_y, 1.0f); | |
789 | |
790 if (shader_tex_transform_location != -1) { | |
791 GLC(Context(), | |
792 Context()->uniform4f(shader_tex_transform_location, | |
793 0.0f, | |
794 0.0f, | |
795 tex_scale_x, | |
796 tex_scale_y)); | |
797 } else if (shader_tex_scale_location != -1) { | |
798 GLC(Context(), | |
799 Context()->uniform2f( | |
800 shader_tex_scale_location, tex_scale_x, tex_scale_y)); | |
801 } else { | |
802 DCHECK(IsContextLost()); | |
803 } | |
804 | |
805 if (shader_mask_sampler_location != -1) { | |
806 DCHECK(shader_mask_tex_coord_scale_location != 1); | |
807 DCHECK(shader_mask_tex_coord_offset_location != 1); | |
808 GLC(Context(), Context()->activeTexture(GL_TEXTURE1)); | |
809 GLC(Context(), Context()->uniform1i(shader_mask_sampler_location, 1)); | |
810 GLC(Context(), | |
811 Context()->uniform2f(shader_mask_tex_coord_offset_location, | |
812 quad->mask_uv_rect.x(), | |
813 quad->mask_uv_rect.y())); | |
814 GLC(Context(), | |
815 Context()->uniform2f(shader_mask_tex_coord_scale_location, | |
816 quad->mask_uv_rect.width() / tex_scale_x, | |
817 quad->mask_uv_rect.height() / tex_scale_y)); | |
818 resource_provider_->BindForSampling( | |
819 quad->mask_resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
820 GLC(Context(), Context()->activeTexture(GL_TEXTURE0)); | |
821 } | |
822 | |
823 if (shader_edge_location != -1) { | |
824 float edge[24]; | |
825 device_layer_edges.ToFloatArray(edge); | |
826 deviceLayerBounds.ToFloatArray(&edge[12]); | |
827 GLC(Context(), Context()->uniform3fv(shader_edge_location, 8, edge)); | |
828 } | |
829 | |
830 // Map device space quad to surface space. contents_device_transform has no 3d | |
831 // component since it was flattened, so we don't need to project. | |
832 gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse, | |
833 device_layer_edges.ToQuadF(), | |
834 &clipped); | |
835 DCHECK(!clipped); | |
836 | |
837 SetShaderOpacity(quad->opacity(), shader_alpha_location); | |
838 SetShaderQuadF(surface_quad, shader_quad_location); | |
839 DrawQuadGeometry( | |
840 frame, quad->quadTransform(), quad->rect, shader_matrix_location); | |
841 | |
842 // Flush the compositor context before the filter bitmap goes out of | |
843 // scope, so the draw gets processed before the filter texture gets deleted. | |
844 if (filter_bitmap.getTexture()) | |
845 context_->flush(); | |
846 } | |
847 | |
848 struct SolidColorProgramUniforms { | |
849 unsigned program; | |
850 unsigned matrix_location; | |
851 unsigned color_location; | |
852 unsigned point_location; | |
853 unsigned tex_scale_location; | |
854 unsigned edge_location; | |
855 }; | |
856 | |
857 template<class T> | |
858 static void SolidColorUniformLocation(T program, | |
859 SolidColorProgramUniforms* uniforms) { | |
860 uniforms->program = program->program(); | |
861 uniforms->matrix_location = program->vertex_shader().matrixLocation(); | |
862 uniforms->color_location = program->fragment_shader().colorLocation(); | |
863 uniforms->point_location = program->vertex_shader().pointLocation(); | |
864 uniforms->tex_scale_location = program->vertex_shader().texScaleLocation(); | |
865 uniforms->edge_location = program->fragment_shader().edgeLocation(); | |
866 } | |
867 | |
868 bool GLRenderer::SetupQuadForAntialiasing( | |
869 const gfx::Transform& device_transform, | |
870 const DrawQuad* quad, | |
871 gfx::QuadF* local_quad, | |
872 float edge[24]) const { | |
873 gfx::Rect tile_rect = quad->visible_rect; | |
874 | |
875 bool clipped = false; | |
876 gfx::QuadF device_layer_quad = MathUtil::MapQuad( | |
877 device_transform, gfx::QuadF(quad->visibleContentRect()), &clipped); | |
878 DCHECK(!clipped); | |
879 | |
880 // TODO(reveman): Axis-aligned is not enough to avoid anti-aliasing. | |
881 // Bounding rectangle for quad also needs to be expressible as an integer | |
882 // rectangle. crbug.com/169374 | |
883 bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); | |
884 bool use_aa = !clipped && !is_axis_aligned_in_target && quad->IsEdge(); | |
885 | |
886 if (!use_aa) | |
887 return false; | |
888 | |
889 LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox())); | |
890 device_layer_bounds.InflateAntiAliasingDistance(); | |
891 | |
892 LayerQuad device_layer_edges(device_layer_quad); | |
893 device_layer_edges.InflateAntiAliasingDistance(); | |
894 | |
895 device_layer_edges.ToFloatArray(edge); | |
896 device_layer_bounds.ToFloatArray(&edge[12]); | |
897 | |
898 gfx::PointF bottom_right = tile_rect.bottom_right(); | |
899 gfx::PointF bottom_left = tile_rect.bottom_left(); | |
900 gfx::PointF top_left = tile_rect.origin(); | |
901 gfx::PointF top_right = tile_rect.top_right(); | |
902 | |
903 // Map points to device space. | |
904 bottom_right = MathUtil::MapPoint(device_transform, bottom_right, &clipped); | |
905 DCHECK(!clipped); | |
906 bottom_left = MathUtil::MapPoint(device_transform, bottom_left, &clipped); | |
907 DCHECK(!clipped); | |
908 top_left = MathUtil::MapPoint(device_transform, top_left, &clipped); | |
909 DCHECK(!clipped); | |
910 top_right = MathUtil::MapPoint(device_transform, top_right, &clipped); | |
911 DCHECK(!clipped); | |
912 | |
913 LayerQuad::Edge bottom_edge(bottom_right, bottom_left); | |
914 LayerQuad::Edge left_edge(bottom_left, top_left); | |
915 LayerQuad::Edge top_edge(top_left, top_right); | |
916 LayerQuad::Edge right_edge(top_right, bottom_right); | |
917 | |
918 // Only apply anti-aliasing to edges not clipped by culling or scissoring. | |
919 if (quad->IsTopEdge() && tile_rect.y() == quad->rect.y()) | |
920 top_edge = device_layer_edges.top(); | |
921 if (quad->IsLeftEdge() && tile_rect.x() == quad->rect.x()) | |
922 left_edge = device_layer_edges.left(); | |
923 if (quad->IsRightEdge() && tile_rect.right() == quad->rect.right()) | |
924 right_edge = device_layer_edges.right(); | |
925 if (quad->IsBottomEdge() && tile_rect.bottom() == quad->rect.bottom()) | |
926 bottom_edge = device_layer_edges.bottom(); | |
927 | |
928 float sign = gfx::QuadF(tile_rect).IsCounterClockwise() ? -1 : 1; | |
929 bottom_edge.scale(sign); | |
930 left_edge.scale(sign); | |
931 top_edge.scale(sign); | |
932 right_edge.scale(sign); | |
933 | |
934 // Create device space quad. | |
935 LayerQuad device_quad(left_edge, top_edge, right_edge, bottom_edge); | |
936 | |
937 // Map device space quad to local space. deviceTransform has no 3d | |
938 // component since it was flattened, so we don't need to project. We should | |
939 // have already checked that the transform was uninvertible above. | |
940 gfx::Transform inverse_device_transform( | |
941 gfx::Transform::kSkipInitialization); | |
942 bool did_invert = device_transform.GetInverse(&inverse_device_transform); | |
943 DCHECK(did_invert); | |
944 *local_quad = MathUtil::MapQuad( | |
945 inverse_device_transform, device_quad.ToQuadF(), &clipped); | |
946 // We should not DCHECK(!clipped) here, because anti-aliasing inflation may | |
947 // cause deviceQuad to become clipped. To our knowledge this scenario does | |
948 // not need to be handled differently than the unclipped case. | |
949 | |
950 return true; | |
951 } | |
952 | |
953 void GLRenderer::DrawSolidColorQuad(const DrawingFrame& frame, | |
954 const SolidColorDrawQuad* quad) { | |
955 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
956 gfx::Rect tile_rect = quad->visible_rect; | |
957 | |
958 gfx::Transform device_transform = | |
959 frame.window_matrix * frame.projection_matrix * quad->quadTransform(); | |
960 device_transform.FlattenTo2d(); | |
961 if (!device_transform.IsInvertible()) | |
962 return; | |
963 | |
964 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); | |
965 float edge[24]; | |
966 bool use_aa = SetupQuadForAntialiasing( | |
967 device_transform, quad, &local_quad, edge); | |
968 | |
969 SolidColorProgramUniforms uniforms; | |
970 if (use_aa) | |
971 SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms); | |
972 else | |
973 SolidColorUniformLocation(GetSolidColorProgram(), &uniforms); | |
974 SetUseProgram(uniforms.program); | |
975 | |
976 SkColor color = quad->color; | |
977 float opacity = quad->opacity(); | |
978 float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity; | |
979 | |
980 GLC(Context(), | |
981 Context()->uniform4f(uniforms.color_location, | |
982 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, | |
983 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, | |
984 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, | |
985 alpha)); | |
986 | |
987 if (use_aa) | |
988 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge)); | |
989 | |
990 // Enable blending when the quad properties require it or if we decided | |
991 // to use antialiasing. | |
992 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa); | |
993 | |
994 // Normalize to tileRect. | |
995 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
996 | |
997 SetShaderQuadF(local_quad, uniforms.point_location); | |
998 | |
999 // The transform and vertex data are used to figure out the extents that the | |
1000 // un-antialiased quad should have and which vertex this is and the float | |
1001 // quad passed in via uniform is the actual geometry that gets used to draw | |
1002 // it. This is why this centered rect is used and not the original quadRect. | |
1003 gfx::RectF centered_rect(gfx::PointF(-0.5f * tile_rect.width(), | |
1004 -0.5f * tile_rect.height()), | |
1005 tile_rect.size()); | |
1006 DrawQuadGeometry(frame, quad->quadTransform(), | |
1007 centered_rect, uniforms.matrix_location); | |
1008 } | |
1009 | |
1010 struct TileProgramUniforms { | |
1011 unsigned program; | |
1012 unsigned sampler_location; | |
1013 unsigned vertex_tex_transform_location; | |
1014 unsigned fragment_tex_transform_location; | |
1015 unsigned edge_location; | |
1016 unsigned matrix_location; | |
1017 unsigned alpha_location; | |
1018 unsigned point_location; | |
1019 }; | |
1020 | |
1021 template <class T> | |
1022 static void TileUniformLocation(T program, TileProgramUniforms* uniforms) { | |
1023 uniforms->program = program->program(); | |
1024 uniforms->vertex_tex_transform_location = | |
1025 program->vertex_shader().vertexTexTransformLocation(); | |
1026 uniforms->matrix_location = program->vertex_shader().matrixLocation(); | |
1027 uniforms->point_location = program->vertex_shader().pointLocation(); | |
1028 | |
1029 uniforms->sampler_location = program->fragment_shader().samplerLocation(); | |
1030 uniforms->alpha_location = program->fragment_shader().alphaLocation(); | |
1031 uniforms->fragment_tex_transform_location = | |
1032 program->fragment_shader().fragmentTexTransformLocation(); | |
1033 uniforms->edge_location = program->fragment_shader().edgeLocation(); | |
1034 } | |
1035 | |
1036 void GLRenderer::DrawTileQuad(const DrawingFrame& frame, | |
1037 const TileDrawQuad* quad) { | |
1038 gfx::Rect tile_rect = quad->visible_rect; | |
1039 | |
1040 gfx::RectF tex_coord_rect = quad->tex_coord_rect; | |
1041 float tex_to_geom_scale_x = quad->rect.width() / tex_coord_rect.width(); | |
1042 float tex_to_geom_scale_y = quad->rect.height() / tex_coord_rect.height(); | |
1043 | |
1044 // tex_coord_rect corresponds to quad_rect, but quadVisibleRect may be | |
1045 // smaller than quad_rect due to occlusion or clipping. Adjust | |
1046 // tex_coord_rect to match. | |
1047 gfx::Vector2d top_left_diff = tile_rect.origin() - quad->rect.origin(); | |
1048 gfx::Vector2d bottom_right_diff = | |
1049 tile_rect.bottom_right() - quad->rect.bottom_right(); | |
1050 tex_coord_rect.Inset(top_left_diff.x() / tex_to_geom_scale_x, | |
1051 top_left_diff.y() / tex_to_geom_scale_y, | |
1052 -bottom_right_diff.x() / tex_to_geom_scale_x, | |
1053 -bottom_right_diff.y() / tex_to_geom_scale_y); | |
1054 | |
1055 gfx::RectF clamp_geom_rect(tile_rect); | |
1056 gfx::RectF clamp_tex_rect(tex_coord_rect); | |
1057 // Clamp texture coordinates to avoid sampling outside the layer | |
1058 // by deflating the tile region half a texel or half a texel | |
1059 // minus epsilon for one pixel layers. The resulting clamp region | |
1060 // is mapped to the unit square by the vertex shader and mapped | |
1061 // back to normalized texture coordinates by the fragment shader | |
1062 // after being clamped to 0-1 range. | |
1063 const float epsilon = 1.0f / 1024.0f; | |
1064 float tex_clamp_x = std::min(0.5f, 0.5f * clamp_tex_rect.width() - epsilon); | |
1065 float tex_clamp_y = std::min(0.5f, 0.5f * clamp_tex_rect.height() - epsilon); | |
1066 float geom_clamp_x = std::min(tex_clamp_x * tex_to_geom_scale_x, | |
1067 0.5f * clamp_geom_rect.width() - epsilon); | |
1068 float geom_clamp_y = std::min(tex_clamp_y * tex_to_geom_scale_y, | |
1069 0.5f * clamp_geom_rect.height() - epsilon); | |
1070 clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y); | |
1071 clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y); | |
1072 | |
1073 // Map clamping rectangle to unit square. | |
1074 float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width(); | |
1075 float vertex_tex_translate_y = | |
1076 -clamp_geom_rect.y() / clamp_geom_rect.height(); | |
1077 float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width(); | |
1078 float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height(); | |
1079 | |
1080 // Map to normalized texture coordinates. | |
1081 gfx::Size texture_size = quad->texture_size; | |
1082 float fragment_tex_translate_x = clamp_tex_rect.x() / texture_size.width(); | |
1083 float fragment_tex_translate_y = clamp_tex_rect.y() / texture_size.height(); | |
1084 float fragment_tex_scale_x = clamp_tex_rect.width() / texture_size.width(); | |
1085 float fragment_tex_scale_y = clamp_tex_rect.height() / texture_size.height(); | |
1086 | |
1087 gfx::Transform device_transform = | |
1088 frame.window_matrix * frame.projection_matrix * quad->quadTransform(); | |
1089 device_transform.FlattenTo2d(); | |
1090 if (!device_transform.IsInvertible()) | |
1091 return; | |
1092 | |
1093 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); | |
1094 float edge[24]; | |
1095 bool use_aa = SetupQuadForAntialiasing( | |
1096 device_transform, quad, &local_quad, edge); | |
1097 | |
1098 TileProgramUniforms uniforms; | |
1099 if (use_aa) { | |
1100 if (quad->swizzle_contents) | |
1101 TileUniformLocation(GetTileProgramSwizzleAA(), &uniforms); | |
1102 else | |
1103 TileUniformLocation(GetTileProgramAA(), &uniforms); | |
1104 } else { | |
1105 if (quad->ShouldDrawWithBlending()) { | |
1106 if (quad->swizzle_contents) | |
1107 TileUniformLocation(GetTileProgramSwizzle(), &uniforms); | |
1108 else | |
1109 TileUniformLocation(GetTileProgram(), &uniforms); | |
1110 } else { | |
1111 if (quad->swizzle_contents) | |
1112 TileUniformLocation(GetTileProgramSwizzleOpaque(), &uniforms); | |
1113 else | |
1114 TileUniformLocation(GetTileProgramOpaque(), &uniforms); | |
1115 } | |
1116 } | |
1117 | |
1118 SetUseProgram(uniforms.program); | |
1119 GLC(Context(), Context()->uniform1i(uniforms.sampler_location, 0)); | |
1120 bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); | |
1121 GLenum filter = (use_aa || scaled || | |
1122 !quad->quadTransform().IsIdentityOrIntegerTranslation()) | |
1123 ? GL_LINEAR | |
1124 : GL_NEAREST; | |
1125 ResourceProvider::ScopedSamplerGL quad_resource_lock( | |
1126 resource_provider_, quad->resource_id, GL_TEXTURE_2D, filter); | |
1127 | |
1128 if (use_aa) { | |
1129 GLC(Context(), Context()->uniform3fv(uniforms.edge_location, 8, edge)); | |
1130 | |
1131 GLC(Context(), | |
1132 Context()->uniform4f(uniforms.vertex_tex_transform_location, | |
1133 vertex_tex_translate_x, | |
1134 vertex_tex_translate_y, | |
1135 vertex_tex_scale_x, | |
1136 vertex_tex_scale_y)); | |
1137 GLC(Context(), | |
1138 Context()->uniform4f(uniforms.fragment_tex_transform_location, | |
1139 fragment_tex_translate_x, | |
1140 fragment_tex_translate_y, | |
1141 fragment_tex_scale_x, | |
1142 fragment_tex_scale_y)); | |
1143 } else { | |
1144 // Move fragment shader transform to vertex shader. We can do this while | |
1145 // still producing correct results as fragment_tex_transform_location | |
1146 // should always be non-negative when tiles are transformed in a way | |
1147 // that could result in sampling outside the layer. | |
1148 vertex_tex_scale_x *= fragment_tex_scale_x; | |
1149 vertex_tex_scale_y *= fragment_tex_scale_y; | |
1150 vertex_tex_translate_x *= fragment_tex_scale_x; | |
1151 vertex_tex_translate_y *= fragment_tex_scale_y; | |
1152 vertex_tex_translate_x += fragment_tex_translate_x; | |
1153 vertex_tex_translate_y += fragment_tex_translate_y; | |
1154 | |
1155 GLC(Context(), | |
1156 Context()->uniform4f(uniforms.vertex_tex_transform_location, | |
1157 vertex_tex_translate_x, | |
1158 vertex_tex_translate_y, | |
1159 vertex_tex_scale_x, | |
1160 vertex_tex_scale_y)); | |
1161 } | |
1162 | |
1163 // Enable blending when the quad properties require it or if we decided | |
1164 // to use antialiasing. | |
1165 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa); | |
1166 | |
1167 // Normalize to tile_rect. | |
1168 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
1169 | |
1170 SetShaderOpacity(quad->opacity(), uniforms.alpha_location); | |
1171 SetShaderQuadF(local_quad, uniforms.point_location); | |
1172 | |
1173 // The transform and vertex data are used to figure out the extents that the | |
1174 // un-antialiased quad should have and which vertex this is and the float | |
1175 // quad passed in via uniform is the actual geometry that gets used to draw | |
1176 // it. This is why this centered rect is used and not the original quad_rect. | |
1177 gfx::RectF centeredRect( | |
1178 gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), | |
1179 tile_rect.size()); | |
1180 DrawQuadGeometry( | |
1181 frame, quad->quadTransform(), centeredRect, uniforms.matrix_location); | |
1182 } | |
1183 | |
1184 void GLRenderer::DrawYUVVideoQuad(const DrawingFrame& frame, | |
1185 const YUVVideoDrawQuad* quad) { | |
1186 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
1187 | |
1188 const VideoYUVProgram* program = GetVideoYUVProgram(); | |
1189 DCHECK(program && (program->initialized() || IsContextLost())); | |
1190 | |
1191 const VideoLayerImpl::FramePlane& y_plane = quad->y_plane; | |
1192 const VideoLayerImpl::FramePlane& u_plane = quad->u_plane; | |
1193 const VideoLayerImpl::FramePlane& v_plane = quad->v_plane; | |
1194 | |
1195 GLC(Context(), Context()->activeTexture(GL_TEXTURE1)); | |
1196 ResourceProvider::ScopedSamplerGL y_plane_lock( | |
1197 resource_provider_, y_plane.resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
1198 GLC(Context(), Context()->activeTexture(GL_TEXTURE2)); | |
1199 ResourceProvider::ScopedSamplerGL u_plane_lock( | |
1200 resource_provider_, u_plane.resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
1201 GLC(Context(), Context()->activeTexture(GL_TEXTURE3)); | |
1202 ResourceProvider::ScopedSamplerGL v_plane_lock( | |
1203 resource_provider_, v_plane.resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
1204 | |
1205 SetUseProgram(program->program()); | |
1206 | |
1207 GLC(Context(), | |
1208 Context()->uniform2f(program->vertex_shader().texScaleLocation(), | |
1209 quad->tex_scale.width(), | |
1210 quad->tex_scale.height())); | |
1211 GLC(Context(), | |
1212 Context()->uniform1i(program->fragment_shader().yTextureLocation(), 1)); | |
1213 GLC(Context(), | |
1214 Context()->uniform1i(program->fragment_shader().uTextureLocation(), 2)); | |
1215 GLC(Context(), | |
1216 Context()->uniform1i(program->fragment_shader().vTextureLocation(), 3)); | |
1217 | |
1218 // These values are magic numbers that are used in the transformation from YUV | |
1219 // to RGB color values. They are taken from the following webpage: | |
1220 // http://www.fourcc.org/fccyvrgb.php | |
1221 float yuv_to_rgb[9] = { | |
1222 1.164f, 1.164f, 1.164f, | |
1223 0.0f, -.391f, 2.018f, | |
1224 1.596f, -.813f, 0.0f, | |
1225 }; | |
1226 GLC(Context(), | |
1227 Context()->uniformMatrix3fv( | |
1228 program->fragment_shader().yuvMatrixLocation(), 1, 0, yuv_to_rgb)); | |
1229 | |
1230 // These values map to 16, 128, and 128 respectively, and are computed | |
1231 // as a fraction over 256 (e.g. 16 / 256 = 0.0625). | |
1232 // They are used in the YUV to RGBA conversion formula: | |
1233 // Y - 16 : Gives 16 values of head and footroom for overshooting | |
1234 // U - 128 : Turns unsigned U into signed U [-128,127] | |
1235 // V - 128 : Turns unsigned V into signed V [-128,127] | |
1236 float yuv_adjust[3] = { -0.0625f, -0.5f, -0.5f, }; | |
1237 GLC(Context(), | |
1238 Context()->uniform3fv( | |
1239 program->fragment_shader().yuvAdjLocation(), 1, yuv_adjust)); | |
1240 | |
1241 SetShaderOpacity(quad->opacity(), program->fragment_shader().alphaLocation()); | |
1242 DrawQuadGeometry(frame, | |
1243 quad->quadTransform(), | |
1244 quad->rect, | |
1245 program->vertex_shader().matrixLocation()); | |
1246 | |
1247 // Reset active texture back to texture 0. | |
1248 GLC(Context(), Context()->activeTexture(GL_TEXTURE0)); | |
1249 } | |
1250 | |
1251 void GLRenderer::DrawStreamVideoQuad(const DrawingFrame& frame, | |
1252 const StreamVideoDrawQuad* quad) { | |
1253 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
1254 | |
1255 static float gl_matrix[16]; | |
1256 | |
1257 DCHECK(capabilities_.using_egl_image); | |
1258 | |
1259 const VideoStreamTextureProgram* program = GetVideoStreamTextureProgram(); | |
1260 SetUseProgram(program->program()); | |
1261 | |
1262 ToGLMatrix(&gl_matrix[0], quad->matrix); | |
1263 GLC(Context(), | |
1264 Context()->uniformMatrix4fv( | |
1265 program->vertex_shader().texMatrixLocation(), 1, false, gl_matrix)); | |
1266 | |
1267 GLC(Context(), | |
1268 Context()->bindTexture(GL_TEXTURE_EXTERNAL_OES, quad->texture_id)); | |
1269 | |
1270 GLC(Context(), | |
1271 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
1272 | |
1273 SetShaderOpacity(quad->opacity(), program->fragment_shader().alphaLocation()); | |
1274 DrawQuadGeometry(frame, | |
1275 quad->quadTransform(), | |
1276 quad->rect, | |
1277 program->vertex_shader().matrixLocation()); | |
1278 } | |
1279 | |
1280 struct TextureProgramBinding { | |
1281 template <class Program> | |
1282 void Set(Program* program, WebKit::WebGraphicsContext3D* context) { | |
1283 DCHECK(program && (program->initialized() || context->isContextLost())); | |
1284 program_id = program->program(); | |
1285 sampler_location = program->fragment_shader().samplerLocation(); | |
1286 matrix_location = program->vertex_shader().matrixLocation(); | |
1287 alpha_location = program->fragment_shader().alphaLocation(); | |
1288 } | |
1289 int program_id; | |
1290 int sampler_location; | |
1291 int matrix_location; | |
1292 int alpha_location; | |
1293 }; | |
1294 | |
1295 struct TexTransformTextureProgramBinding : TextureProgramBinding { | |
1296 template <class Program> | |
1297 void Set(Program* program, WebKit::WebGraphicsContext3D* context) { | |
1298 TextureProgramBinding::Set(program, context); | |
1299 tex_transform_location = program->vertex_shader().texTransformLocation(); | |
1300 vertex_opacity_location = program->vertex_shader().vertexOpacityLocation(); | |
1301 } | |
1302 int tex_transform_location; | |
1303 int vertex_opacity_location; | |
1304 }; | |
1305 | |
1306 void GLRenderer::FlushTextureQuadCache() { | |
1307 // Check to see if we have anything to draw. | |
1308 if (draw_cache_.program_id == 0) | |
1309 return; | |
1310 | |
1311 // Set the correct blending mode. | |
1312 SetBlendEnabled(draw_cache_.needs_blending); | |
1313 | |
1314 // Bind the program to the GL state. | |
1315 SetUseProgram(draw_cache_.program_id); | |
1316 | |
1317 // Bind the correct texture sampler location. | |
1318 GLC(Context(), Context()->uniform1i(draw_cache_.sampler_location, 0)); | |
1319 | |
1320 // Assume the current active textures is 0. | |
1321 ResourceProvider::ScopedReadLockGL locked_quad(resource_provider_, | |
1322 draw_cache_.resource_id); | |
1323 GLC(Context(), | |
1324 Context()->bindTexture(GL_TEXTURE_2D, locked_quad.texture_id())); | |
1325 | |
1326 // set up premultiplied alpha. | |
1327 if (!draw_cache_.use_premultiplied_alpha) { | |
1328 // As it turns out, the premultiplied alpha blending function (ONE, | |
1329 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to | |
1330 // anything less than 1.0f if it is initialized to that value! Therefore, | |
1331 // premultipliedAlpha being false is the first situation we can generally | |
1332 // see an alpha channel less than 1.0f coming out of the compositor. This is | |
1333 // causing platform differences in some layout tests (see | |
1334 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use | |
1335 // a separate blend function for the alpha channel to avoid modifying it. | |
1336 // Don't use colorMask for this as it has performance implications on some | |
1337 // platforms. | |
1338 GLC(Context(), | |
1339 Context()->blendFuncSeparate( | |
1340 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); | |
1341 } | |
1342 | |
1343 COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), struct_is_densely_packed); | |
1344 COMPILE_ASSERT(sizeof(Float16) == 16 * sizeof(float), | |
1345 struct_is_densely_packed); | |
1346 | |
1347 // Upload the tranforms for both points and uvs. | |
1348 GLC(context_, | |
1349 context_->uniformMatrix4fv( | |
1350 static_cast<int>(draw_cache_.matrix_location), | |
1351 static_cast<int>(draw_cache_.matrix_data.size()), | |
1352 false, | |
1353 reinterpret_cast<float*>(&draw_cache_.matrix_data.front()))); | |
1354 GLC(context_, | |
1355 context_->uniform4fv( | |
1356 static_cast<int>(draw_cache_.uv_xform_location), | |
1357 static_cast<int>(draw_cache_.uv_xform_data.size()), | |
1358 reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()))); | |
1359 GLC(context_, | |
1360 context_->uniform1fv( | |
1361 static_cast<int>(draw_cache_.vertex_opacity_location), | |
1362 static_cast<int>(draw_cache_.vertex_opacity_data.size()), | |
1363 static_cast<float*>(&draw_cache_.vertex_opacity_data.front()))); | |
1364 | |
1365 // Draw the quads! | |
1366 GLC(context_, | |
1367 context_->drawElements(GL_TRIANGLES, | |
1368 6 * draw_cache_.matrix_data.size(), | |
1369 GL_UNSIGNED_SHORT, | |
1370 0)); | |
1371 | |
1372 // Clean up after ourselves (reset state set above). | |
1373 if (!draw_cache_.use_premultiplied_alpha) | |
1374 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
1375 | |
1376 // Clear the cache. | |
1377 draw_cache_.program_id = 0; | |
1378 draw_cache_.uv_xform_data.resize(0); | |
1379 draw_cache_.vertex_opacity_data.resize(0); | |
1380 draw_cache_.matrix_data.resize(0); | |
1381 } | |
1382 | |
1383 void GLRenderer::EnqueueTextureQuad(const DrawingFrame& frame, | |
1384 const TextureDrawQuad* quad) { | |
1385 // Choose the correct texture program binding | |
1386 TexTransformTextureProgramBinding binding; | |
1387 if (quad->flipped) | |
1388 binding.Set(GetTextureProgramFlip(), Context()); | |
1389 else | |
1390 binding.Set(GetTextureProgram(), Context()); | |
1391 | |
1392 int resource_id = quad->resource_id; | |
1393 | |
1394 if (draw_cache_.program_id != binding.program_id || | |
1395 draw_cache_.resource_id != resource_id || | |
1396 draw_cache_.use_premultiplied_alpha != quad->premultiplied_alpha || | |
1397 draw_cache_.needs_blending != quad->ShouldDrawWithBlending() || | |
1398 draw_cache_.matrix_data.size() >= 8) { | |
1399 FlushTextureQuadCache(); | |
1400 draw_cache_.program_id = binding.program_id; | |
1401 draw_cache_.resource_id = resource_id; | |
1402 draw_cache_.use_premultiplied_alpha = quad->premultiplied_alpha; | |
1403 draw_cache_.needs_blending = quad->ShouldDrawWithBlending(); | |
1404 | |
1405 draw_cache_.uv_xform_location = binding.tex_transform_location; | |
1406 draw_cache_.vertex_opacity_location = binding.vertex_opacity_location; | |
1407 draw_cache_.matrix_location = binding.matrix_location; | |
1408 draw_cache_.sampler_location = binding.sampler_location; | |
1409 } | |
1410 | |
1411 // Generate the uv-transform | |
1412 gfx::PointF uv0 = quad->uv_top_left; | |
1413 gfx::PointF uv1 = quad->uv_bottom_right; | |
1414 Float4 uv = { { uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y() } }; | |
1415 draw_cache_.uv_xform_data.push_back(uv); | |
1416 | |
1417 // Generate the vertex opacity | |
1418 const float opacity = quad->opacity(); | |
1419 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity); | |
1420 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity); | |
1421 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity); | |
1422 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity); | |
1423 | |
1424 // Generate the transform matrix | |
1425 gfx::Transform quad_rect_matrix; | |
1426 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); | |
1427 quad_rect_matrix = frame.projection_matrix * quad_rect_matrix; | |
1428 | |
1429 Float16 m; | |
1430 quad_rect_matrix.matrix().asColMajorf(m.data); | |
1431 draw_cache_.matrix_data.push_back(m); | |
1432 } | |
1433 | |
1434 void GLRenderer::DrawTextureQuad(const DrawingFrame& frame, | |
1435 const TextureDrawQuad* quad) { | |
1436 TexTransformTextureProgramBinding binding; | |
1437 if (quad->flipped) | |
1438 binding.Set(GetTextureProgramFlip(), Context()); | |
1439 else | |
1440 binding.Set(GetTextureProgram(), Context()); | |
1441 SetUseProgram(binding.program_id); | |
1442 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0)); | |
1443 gfx::PointF uv0 = quad->uv_top_left; | |
1444 gfx::PointF uv1 = quad->uv_bottom_right; | |
1445 GLC(Context(), | |
1446 Context()->uniform4f(binding.tex_transform_location, | |
1447 uv0.x(), | |
1448 uv0.y(), | |
1449 uv1.x() - uv0.x(), | |
1450 uv1.y() - uv0.y())); | |
1451 | |
1452 GLC(Context(), | |
1453 Context()->uniform1fv( | |
1454 binding.vertex_opacity_location, 4, quad->vertex_opacity)); | |
1455 | |
1456 ResourceProvider::ScopedSamplerGL quad_resource_lock( | |
1457 resource_provider_, quad->resource_id, GL_TEXTURE_2D, GL_LINEAR); | |
1458 | |
1459 if (!quad->premultiplied_alpha) { | |
1460 // As it turns out, the premultiplied alpha blending function (ONE, | |
1461 // ONE_MINUS_SRC_ALPHA) will never cause the alpha channel to be set to | |
1462 // anything less than 1.0f if it is initialized to that value! Therefore, | |
1463 // premultipliedAlpha being false is the first situation we can generally | |
1464 // see an alpha channel less than 1.0f coming out of the compositor. This is | |
1465 // causing platform differences in some layout tests (see | |
1466 // https://bugs.webkit.org/show_bug.cgi?id=82412), so in this situation, use | |
1467 // a separate blend function for the alpha channel to avoid modifying it. | |
1468 // Don't use colorMask for this as it has performance implications on some | |
1469 // platforms. | |
1470 GLC(Context(), | |
1471 Context()->blendFuncSeparate( | |
1472 GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE)); | |
1473 } | |
1474 | |
1475 DrawQuadGeometry( | |
1476 frame, quad->quadTransform(), quad->rect, binding.matrix_location); | |
1477 | |
1478 if (!quad->premultiplied_alpha) | |
1479 GLC(context_, context_->blendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
1480 } | |
1481 | |
1482 void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame& frame, | |
1483 const IOSurfaceDrawQuad* quad) { | |
1484 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
1485 | |
1486 TexTransformTextureProgramBinding binding; | |
1487 binding.Set(GetTextureIOSurfaceProgram(), Context()); | |
1488 | |
1489 SetUseProgram(binding.program_id); | |
1490 GLC(Context(), Context()->uniform1i(binding.sampler_location, 0)); | |
1491 if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) { | |
1492 GLC(Context(), | |
1493 Context()->uniform4f(binding.tex_transform_location, | |
1494 0, | |
1495 quad->io_surface_size.height(), | |
1496 quad->io_surface_size.width(), | |
1497 quad->io_surface_size.height() * -1.0f)); | |
1498 } else { | |
1499 GLC(Context(), | |
1500 Context()->uniform4f(binding.tex_transform_location, | |
1501 0, | |
1502 0, | |
1503 quad->io_surface_size.width(), | |
1504 quad->io_surface_size.height())); | |
1505 } | |
1506 | |
1507 const float vertex_opacity[] = { quad->opacity(), quad->opacity(), | |
1508 quad->opacity(), quad->opacity() }; | |
1509 GLC(Context(), | |
1510 Context()->uniform1fv( | |
1511 binding.vertex_opacity_location, 4, vertex_opacity)); | |
1512 | |
1513 GLC(Context(), | |
1514 Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, | |
1515 quad->io_surface_texture_id)); | |
1516 | |
1517 DrawQuadGeometry( | |
1518 frame, quad->quadTransform(), quad->rect, binding.matrix_location); | |
1519 | |
1520 GLC(Context(), Context()->bindTexture(GL_TEXTURE_RECTANGLE_ARB, 0)); | |
1521 } | |
1522 | |
1523 void GLRenderer::FinishDrawingFrame(DrawingFrame& frame) { | |
1524 current_framebuffer_lock_.reset(); | |
1525 swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame.root_damage_rect)); | |
1526 | |
1527 GLC(context_, context_->disable(GL_BLEND)); | |
1528 blend_shadow_ = false; | |
1529 | |
1530 if (Settings().compositorFrameMessage) { | |
1531 CompositorFrame compositor_frame; | |
1532 compositor_frame.metadata = client_->MakeCompositorFrameMetadata(); | |
1533 output_surface_->SendFrameToParentCompositor(&compositor_frame); | |
1534 } | |
1535 } | |
1536 | |
1537 void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); } | |
1538 | |
1539 bool GLRenderer::FlippedFramebuffer() const { return true; } | |
1540 | |
1541 void GLRenderer::EnsureScissorTestEnabled() { | |
1542 if (is_scissor_enabled_) | |
1543 return; | |
1544 | |
1545 FlushTextureQuadCache(); | |
1546 GLC(context_, context_->enable(GL_SCISSOR_TEST)); | |
1547 is_scissor_enabled_ = true; | |
1548 } | |
1549 | |
1550 void GLRenderer::EnsureScissorTestDisabled() { | |
1551 if (!is_scissor_enabled_) | |
1552 return; | |
1553 | |
1554 FlushTextureQuadCache(); | |
1555 GLC(context_, context_->disable(GL_SCISSOR_TEST)); | |
1556 is_scissor_enabled_ = false; | |
1557 } | |
1558 | |
1559 void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) { | |
1560 transform.matrix().asColMajorf(gl_matrix); | |
1561 } | |
1562 | |
1563 void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) { | |
1564 if (quad_location == -1) | |
1565 return; | |
1566 | |
1567 float point[8]; | |
1568 point[0] = quad.p1().x(); | |
1569 point[1] = quad.p1().y(); | |
1570 point[2] = quad.p2().x(); | |
1571 point[3] = quad.p2().y(); | |
1572 point[4] = quad.p3().x(); | |
1573 point[5] = quad.p3().y(); | |
1574 point[6] = quad.p4().x(); | |
1575 point[7] = quad.p4().y(); | |
1576 GLC(context_, context_->uniform2fv(quad_location, 4, point)); | |
1577 } | |
1578 | |
1579 void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) { | |
1580 if (alpha_location != -1) | |
1581 GLC(context_, context_->uniform1f(alpha_location, opacity)); | |
1582 } | |
1583 | |
1584 void GLRenderer::SetBlendEnabled(bool enabled) { | |
1585 if (enabled == blend_shadow_) | |
1586 return; | |
1587 | |
1588 if (enabled) | |
1589 GLC(context_, context_->enable(GL_BLEND)); | |
1590 else | |
1591 GLC(context_, context_->disable(GL_BLEND)); | |
1592 blend_shadow_ = enabled; | |
1593 } | |
1594 | |
1595 void GLRenderer::SetUseProgram(unsigned program) { | |
1596 if (program == program_shadow_) | |
1597 return; | |
1598 GLC(context_, context_->useProgram(program)); | |
1599 program_shadow_ = program; | |
1600 } | |
1601 | |
1602 void GLRenderer::DrawQuadGeometry(const DrawingFrame& frame, | |
1603 const gfx::Transform& draw_transform, | |
1604 const gfx::RectF& quad_rect, | |
1605 int matrix_location) { | |
1606 gfx::Transform quad_rect_matrix; | |
1607 QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect); | |
1608 static float gl_matrix[16]; | |
1609 ToGLMatrix(&gl_matrix[0], frame.projection_matrix * quad_rect_matrix); | |
1610 GLC(context_, | |
1611 context_->uniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0])); | |
1612 | |
1613 GLC(context_, context_->drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); | |
1614 } | |
1615 | |
1616 void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame& frame, | |
1617 int texture_id, | |
1618 gfx::Rect rect, | |
1619 const gfx::Transform& draw_matrix) { | |
1620 const RenderPassProgram* program = GetRenderPassProgram(); | |
1621 | |
1622 GLC(Context(), Context()->bindTexture(GL_TEXTURE_2D, texture_id)); | |
1623 | |
1624 SetUseProgram(program->program()); | |
1625 GLC(Context(), | |
1626 Context()->uniform1i(program->fragment_shader().samplerLocation(), 0)); | |
1627 GLC(Context(), | |
1628 Context()->uniform4f(program->vertex_shader().texTransformLocation(), | |
1629 0.0f, | |
1630 0.0f, | |
1631 1.0f, | |
1632 1.0f)); | |
1633 SetShaderOpacity(1, program->fragment_shader().alphaLocation()); | |
1634 DrawQuadGeometry( | |
1635 frame, draw_matrix, rect, program->vertex_shader().matrixLocation()); | |
1636 } | |
1637 | |
1638 void GLRenderer::Finish() { | |
1639 TRACE_EVENT0("cc", "GLRenderer::finish"); | |
1640 context_->finish(); | |
1641 } | |
1642 | |
1643 bool GLRenderer::SwapBuffers() { | |
1644 DCHECK(visible_); | |
1645 DCHECK(!is_backbuffer_discarded_); | |
1646 | |
1647 TRACE_EVENT0("cc", "GLRenderer::swapBuffers"); | |
1648 // We're done! Time to swapbuffers! | |
1649 | |
1650 if (capabilities_.using_partial_swap) { | |
1651 // If supported, we can save significant bandwidth by only swapping the | |
1652 // damaged/scissored region (clamped to the viewport) | |
1653 swap_buffer_rect_.Intersect(gfx::Rect(gfx::Point(), ViewportSize())); | |
1654 int flipped_y_pos_of_rect_bottom = | |
1655 ViewportHeight() - swap_buffer_rect_.y() - swap_buffer_rect_.height(); | |
1656 output_surface_->PostSubBuffer(gfx::Rect(swap_buffer_rect_.x(), | |
1657 flipped_y_pos_of_rect_bottom, | |
1658 swap_buffer_rect_.width(), | |
1659 swap_buffer_rect_.height())); | |
1660 } else { | |
1661 output_surface_->SwapBuffers(); | |
1662 } | |
1663 | |
1664 swap_buffer_rect_ = gfx::Rect(); | |
1665 | |
1666 // We don't have real fences, so we mark read fences as passed | |
1667 // assuming a double-buffered GPU pipeline. A texture can be | |
1668 // written to after one full frame has past since it was last read. | |
1669 if (last_swap_fence_) | |
1670 static_cast<SimpleSwapFence*>(last_swap_fence_.get())->SetHasPassed(); | |
1671 last_swap_fence_ = resource_provider_->GetReadLockFence(); | |
1672 resource_provider_->SetReadLockFence(new SimpleSwapFence()); | |
1673 | |
1674 return true; | |
1675 } | |
1676 | |
1677 void GLRenderer::ReceiveCompositorFrameAck(const CompositorFrameAck& ack) { | |
1678 onSwapBuffersComplete(); | |
1679 } | |
1680 | |
1681 void GLRenderer::onSwapBuffersComplete() { client_->OnSwapBuffersComplete(); } | |
1682 | |
1683 void GLRenderer::onMemoryAllocationChanged( | |
1684 WebGraphicsMemoryAllocation allocation) { | |
1685 // Just ignore the memory manager when it says to set the limit to zero | |
1686 // bytes. This will happen when the memory manager thinks that the renderer | |
1687 // is not visible (which the renderer knows better). | |
1688 if (allocation.bytesLimitWhenVisible) { | |
1689 ManagedMemoryPolicy policy( | |
1690 allocation.bytesLimitWhenVisible, | |
1691 PriorityCutoff(allocation.priorityCutoffWhenVisible), | |
1692 allocation.bytesLimitWhenNotVisible, | |
1693 PriorityCutoff(allocation.priorityCutoffWhenNotVisible)); | |
1694 | |
1695 if (allocation.enforceButDoNotKeepAsPolicy) | |
1696 client_->EnforceManagedMemoryPolicy(policy); | |
1697 else | |
1698 client_->SetManagedMemoryPolicy(policy); | |
1699 } | |
1700 | |
1701 bool old_discard_backbuffer_when_not_visible = | |
1702 discard_backbuffer_when_not_visible_; | |
1703 discard_backbuffer_when_not_visible_ = !allocation.suggestHaveBackbuffer; | |
1704 EnforceMemoryPolicy(); | |
1705 if (allocation.enforceButDoNotKeepAsPolicy) | |
1706 discard_backbuffer_when_not_visible_ = | |
1707 old_discard_backbuffer_when_not_visible; | |
1708 } | |
1709 | |
1710 ManagedMemoryPolicy::PriorityCutoff GLRenderer::PriorityCutoff( | |
1711 WebKit::WebGraphicsMemoryAllocation::PriorityCutoff priority_cutoff) { | |
1712 // This is simple a 1:1 map, the names differ only because the WebKit names | |
1713 // should be to match the cc names. | |
1714 switch (priority_cutoff) { | |
1715 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing: | |
1716 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING; | |
1717 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly: | |
1718 return ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY; | |
1719 case WebKit::WebGraphicsMemoryAllocation:: | |
1720 PriorityCutoffAllowVisibleAndNearby: | |
1721 return ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE; | |
1722 case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything: | |
1723 return ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING; | |
1724 } | |
1725 NOTREACHED(); | |
1726 return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING; | |
1727 } | |
1728 | |
1729 void GLRenderer::EnforceMemoryPolicy() { | |
1730 if (!visible_) { | |
1731 TRACE_EVENT0("cc", "GLRenderer::enforceMemoryPolicy dropping resources"); | |
1732 ReleaseRenderPassTextures(); | |
1733 if (discard_backbuffer_when_not_visible_) | |
1734 DiscardBackbuffer(); | |
1735 resource_provider_->ReleaseCachedData(); | |
1736 GLC(context_, context_->flush()); | |
1737 } | |
1738 } | |
1739 | |
1740 void GLRenderer::DiscardBackbuffer() { | |
1741 if (is_backbuffer_discarded_) | |
1742 return; | |
1743 | |
1744 output_surface_->DiscardBackbuffer(); | |
1745 | |
1746 is_backbuffer_discarded_ = true; | |
1747 | |
1748 // Damage tracker needs a full reset every time framebuffer is discarded. | |
1749 client_->SetFullRootLayerDamage(); | |
1750 } | |
1751 | |
1752 void GLRenderer::EnsureBackbuffer() { | |
1753 if (!is_backbuffer_discarded_) | |
1754 return; | |
1755 | |
1756 output_surface_->EnsureBackbuffer(); | |
1757 is_backbuffer_discarded_ = false; | |
1758 } | |
1759 | |
1760 void GLRenderer::onContextLost() { client_->DidLoseOutputSurface(); } | |
1761 | |
1762 void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) { | |
1763 DCHECK(rect.right() <= ViewportWidth()); | |
1764 DCHECK(rect.bottom() <= ViewportHeight()); | |
1765 | |
1766 if (!pixels) | |
1767 return; | |
1768 | |
1769 MakeContextCurrent(); | |
1770 | |
1771 bool do_workaround = NeedsIOSurfaceReadbackWorkaround(); | |
1772 | |
1773 GLuint temporary_texture = 0; | |
1774 GLuint temporary_fbo = 0; | |
1775 | |
1776 if (do_workaround) { | |
1777 // On Mac OS X, calling glReadPixels against an FBO whose color attachment | |
1778 // is an IOSurface-backed texture causes corruption of future glReadPixels | |
1779 // calls, even those on different OpenGL contexts. It is believed that this | |
1780 // is the root cause of top crasher | |
1781 // http://crbug.com/99393. <rdar://problem/10949687> | |
1782 | |
1783 temporary_texture = context_->createTexture(); | |
1784 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, temporary_texture)); | |
1785 GLC(context_, | |
1786 context_->texParameteri( | |
1787 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | |
1788 GLC(context_, | |
1789 context_->texParameteri( | |
1790 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | |
1791 GLC(context_, | |
1792 context_->texParameteri( | |
1793 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); | |
1794 GLC(context_, | |
1795 context_->texParameteri( | |
1796 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); | |
1797 // Copy the contents of the current (IOSurface-backed) framebuffer into a | |
1798 // temporary texture. | |
1799 GLC(context_, | |
1800 context_->copyTexImage2D(GL_TEXTURE_2D, | |
1801 0, | |
1802 GL_RGBA, | |
1803 0, | |
1804 0, | |
1805 ViewportSize().width(), | |
1806 ViewportSize().height(), | |
1807 0)); | |
1808 temporary_fbo = context_->createFramebuffer(); | |
1809 // Attach this texture to an FBO, and perform the readback from that FBO. | |
1810 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, temporary_fbo)); | |
1811 GLC(context_, | |
1812 context_->framebufferTexture2D(GL_FRAMEBUFFER, | |
1813 GL_COLOR_ATTACHMENT0, | |
1814 GL_TEXTURE_2D, | |
1815 temporary_texture, | |
1816 0)); | |
1817 | |
1818 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) == | |
1819 GL_FRAMEBUFFER_COMPLETE); | |
1820 } | |
1821 | |
1822 scoped_array<uint8_t> src_pixels( | |
1823 new uint8_t[rect.width() * rect.height() * 4]); | |
1824 GLC(context_, | |
1825 context_->readPixels(rect.x(), | |
1826 ViewportSize().height() - rect.bottom(), | |
1827 rect.width(), | |
1828 rect.height(), | |
1829 GL_RGBA, | |
1830 GL_UNSIGNED_BYTE, | |
1831 src_pixels.get())); | |
1832 | |
1833 uint8_t* dest_pixels = static_cast<uint8_t*>(pixels); | |
1834 size_t row_bytes = rect.width() * 4; | |
1835 int num_rows = rect.height(); | |
1836 size_t total_bytes = num_rows * row_bytes; | |
1837 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) { | |
1838 // Flip Y axis. | |
1839 size_t src_y = total_bytes - dest_y - row_bytes; | |
1840 // Swizzle BGRA -> RGBA. | |
1841 for (size_t x = 0; x < row_bytes; x += 4) { | |
1842 dest_pixels[dest_y + (x + 0)] = src_pixels.get()[src_y + (x + 2)]; | |
1843 dest_pixels[dest_y + (x + 1)] = src_pixels.get()[src_y + (x + 1)]; | |
1844 dest_pixels[dest_y + (x + 2)] = src_pixels.get()[src_y + (x + 0)]; | |
1845 dest_pixels[dest_y + (x + 3)] = src_pixels.get()[src_y + (x + 3)]; | |
1846 } | |
1847 } | |
1848 | |
1849 if (do_workaround) { | |
1850 // Clean up. | |
1851 GLC(context_, context_->bindFramebuffer(GL_FRAMEBUFFER, 0)); | |
1852 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, 0)); | |
1853 GLC(context_, context_->deleteFramebuffer(temporary_fbo)); | |
1854 GLC(context_, context_->deleteTexture(temporary_texture)); | |
1855 } | |
1856 | |
1857 EnforceMemoryPolicy(); | |
1858 } | |
1859 | |
1860 bool GLRenderer::GetFramebufferTexture(ScopedResource* texture, | |
1861 gfx::Rect device_rect) { | |
1862 DCHECK(!texture->id() || (texture->size() == device_rect.size() && | |
1863 texture->format() == GL_RGB)); | |
1864 | |
1865 if (!texture->id() && !texture->Allocate(device_rect.size(), | |
1866 GL_RGB, | |
1867 ResourceProvider::TextureUsageAny)) | |
1868 return false; | |
1869 | |
1870 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, texture->id()); | |
1871 GLC(context_, context_->bindTexture(GL_TEXTURE_2D, lock.texture_id())); | |
1872 GLC(context_, | |
1873 context_->copyTexImage2D(GL_TEXTURE_2D, | |
1874 0, | |
1875 texture->format(), | |
1876 device_rect.x(), | |
1877 device_rect.y(), | |
1878 device_rect.width(), | |
1879 device_rect.height(), | |
1880 0)); | |
1881 return true; | |
1882 } | |
1883 | |
1884 bool GLRenderer::UseScopedTexture(DrawingFrame& frame, | |
1885 const ScopedResource* texture, | |
1886 gfx::Rect viewport_rect) { | |
1887 DCHECK(texture->id()); | |
1888 frame.current_render_pass = 0; | |
1889 frame.current_texture = texture; | |
1890 | |
1891 return BindFramebufferToTexture(frame, texture, viewport_rect); | |
1892 } | |
1893 | |
1894 void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame& frame) { | |
1895 current_framebuffer_lock_.reset(); | |
1896 output_surface_->BindFramebuffer(); | |
1897 } | |
1898 | |
1899 bool GLRenderer::BindFramebufferToTexture(DrawingFrame& frame, | |
1900 const ScopedResource* texture, | |
1901 gfx::Rect framebuffer_rect) { | |
1902 DCHECK(texture->id()); | |
1903 | |
1904 GLC(context_, | |
1905 context_->bindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_)); | |
1906 current_framebuffer_lock_ = | |
1907 make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL( | |
1908 resource_provider_, texture->id())); | |
1909 unsigned texture_id = current_framebuffer_lock_->texture_id(); | |
1910 GLC(context_, | |
1911 context_->framebufferTexture2D( | |
1912 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0)); | |
1913 | |
1914 DCHECK(context_->checkFramebufferStatus(GL_FRAMEBUFFER) == | |
1915 GL_FRAMEBUFFER_COMPLETE || IsContextLost()); | |
1916 | |
1917 InitializeMatrices(frame, framebuffer_rect, false); | |
1918 SetDrawViewportSize(framebuffer_rect.size()); | |
1919 | |
1920 return true; | |
1921 } | |
1922 | |
1923 void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) { | |
1924 EnsureScissorTestEnabled(); | |
1925 | |
1926 // Don't unnecessarily ask the context to change the scissor, because it | |
1927 // may cause undesired GPU pipeline flushes. | |
1928 if (scissor_rect == scissor_rect_) | |
1929 return; | |
1930 | |
1931 scissor_rect_ = scissor_rect; | |
1932 FlushTextureQuadCache(); | |
1933 GLC(context_, | |
1934 context_->scissor(scissor_rect.x(), | |
1935 scissor_rect.y(), | |
1936 scissor_rect.width(), | |
1937 scissor_rect.height())); | |
1938 } | |
1939 | |
1940 void GLRenderer::SetDrawViewportSize(gfx::Size viewport_size) { | |
1941 GLC(context_, | |
1942 context_->viewport(0, 0, viewport_size.width(), viewport_size.height())); | |
1943 } | |
1944 | |
1945 bool GLRenderer::MakeContextCurrent() { return context_->makeContextCurrent(); } | |
1946 | |
1947 bool GLRenderer::InitializeSharedObjects() { | |
1948 TRACE_EVENT0("cc", "GLRenderer::initializeSharedObjects"); | |
1949 MakeContextCurrent(); | |
1950 | |
1951 // Create an FBO for doing offscreen rendering. | |
1952 GLC(context_, offscreen_framebuffer_id_ = context_->createFramebuffer()); | |
1953 | |
1954 // We will always need these programs to render, so create the programs | |
1955 // eagerly so that the shader compilation can start while we do other work. | |
1956 // Other programs are created lazily on first access. | |
1957 shared_geometry_ = | |
1958 make_scoped_ptr(new GeometryBinding(context_, QuadVertexRect())); | |
1959 render_pass_program_ = make_scoped_ptr(new RenderPassProgram(context_)); | |
1960 tile_program_ = make_scoped_ptr(new TileProgram(context_)); | |
1961 tile_program_opaque_ = make_scoped_ptr(new TileProgramOpaque(context_)); | |
1962 | |
1963 GLC(context_, context_->flush()); | |
1964 | |
1965 return true; | |
1966 } | |
1967 | |
1968 const GLRenderer::TileCheckerboardProgram* | |
1969 GLRenderer::GetTileCheckerboardProgram() { | |
1970 if (!tile_checkerboard_program_) { | |
1971 tile_checkerboard_program_ = | |
1972 make_scoped_ptr(new TileCheckerboardProgram(context_)); | |
1973 } | |
1974 if (!tile_checkerboard_program_->initialized()) { | |
1975 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize"); | |
1976 tile_checkerboard_program_->Initialize(context_, is_using_bind_uniform_); | |
1977 } | |
1978 return tile_checkerboard_program_.get(); | |
1979 } | |
1980 | |
1981 const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() { | |
1982 if (!debug_border_program_) | |
1983 debug_border_program_ = make_scoped_ptr(new DebugBorderProgram(context_)); | |
1984 if (!debug_border_program_->initialized()) { | |
1985 TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize"); | |
1986 debug_border_program_->Initialize(context_, is_using_bind_uniform_); | |
1987 } | |
1988 return debug_border_program_.get(); | |
1989 } | |
1990 | |
1991 const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() { | |
1992 if (!solid_color_program_) | |
1993 solid_color_program_ = make_scoped_ptr(new SolidColorProgram(context_)); | |
1994 if (!solid_color_program_->initialized()) { | |
1995 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize"); | |
1996 solid_color_program_->Initialize(context_, is_using_bind_uniform_); | |
1997 } | |
1998 return solid_color_program_.get(); | |
1999 } | |
2000 | |
2001 const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() { | |
2002 if (!solid_color_program_aa_) { | |
2003 solid_color_program_aa_ = | |
2004 make_scoped_ptr(new SolidColorProgramAA(context_)); | |
2005 } | |
2006 if (!solid_color_program_aa_->initialized()) { | |
2007 TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize"); | |
2008 solid_color_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
2009 } | |
2010 return solid_color_program_aa_.get(); | |
2011 } | |
2012 | |
2013 const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram() { | |
2014 DCHECK(render_pass_program_); | |
2015 if (!render_pass_program_->initialized()) { | |
2016 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize"); | |
2017 render_pass_program_->Initialize(context_, is_using_bind_uniform_); | |
2018 } | |
2019 return render_pass_program_.get(); | |
2020 } | |
2021 | |
2022 const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA() { | |
2023 if (!render_pass_program_aa_) | |
2024 render_pass_program_aa_ = | |
2025 make_scoped_ptr(new RenderPassProgramAA(context_)); | |
2026 if (!render_pass_program_aa_->initialized()) { | |
2027 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize"); | |
2028 render_pass_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
2029 } | |
2030 return render_pass_program_aa_.get(); | |
2031 } | |
2032 | |
2033 const GLRenderer::RenderPassMaskProgram* | |
2034 GLRenderer::GetRenderPassMaskProgram() { | |
2035 if (!render_pass_mask_program_) | |
2036 render_pass_mask_program_ = | |
2037 make_scoped_ptr(new RenderPassMaskProgram(context_)); | |
2038 if (!render_pass_mask_program_->initialized()) { | |
2039 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize"); | |
2040 render_pass_mask_program_->Initialize(context_, is_using_bind_uniform_); | |
2041 } | |
2042 return render_pass_mask_program_.get(); | |
2043 } | |
2044 | |
2045 const GLRenderer::RenderPassMaskProgramAA* | |
2046 GLRenderer::GetRenderPassMaskProgramAA() { | |
2047 if (!render_pass_mask_program_aa_) | |
2048 render_pass_mask_program_aa_ = | |
2049 make_scoped_ptr(new RenderPassMaskProgramAA(context_)); | |
2050 if (!render_pass_mask_program_aa_->initialized()) { | |
2051 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize"); | |
2052 render_pass_mask_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
2053 } | |
2054 return render_pass_mask_program_aa_.get(); | |
2055 } | |
2056 | |
2057 const GLRenderer::TileProgram* GLRenderer::GetTileProgram() { | |
2058 DCHECK(tile_program_); | |
2059 if (!tile_program_->initialized()) { | |
2060 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize"); | |
2061 tile_program_->Initialize(context_, is_using_bind_uniform_); | |
2062 } | |
2063 return tile_program_.get(); | |
2064 } | |
2065 | |
2066 const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque() { | |
2067 DCHECK(tile_program_opaque_); | |
2068 if (!tile_program_opaque_->initialized()) { | |
2069 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize"); | |
2070 tile_program_opaque_->Initialize(context_, is_using_bind_uniform_); | |
2071 } | |
2072 return tile_program_opaque_.get(); | |
2073 } | |
2074 | |
2075 const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA() { | |
2076 if (!tile_program_aa_) | |
2077 tile_program_aa_ = make_scoped_ptr(new TileProgramAA(context_)); | |
2078 if (!tile_program_aa_->initialized()) { | |
2079 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize"); | |
2080 tile_program_aa_->Initialize(context_, is_using_bind_uniform_); | |
2081 } | |
2082 return tile_program_aa_.get(); | |
2083 } | |
2084 | |
2085 const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle() { | |
2086 if (!tile_program_swizzle_) | |
2087 tile_program_swizzle_ = make_scoped_ptr(new TileProgramSwizzle(context_)); | |
2088 if (!tile_program_swizzle_->initialized()) { | |
2089 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize"); | |
2090 tile_program_swizzle_->Initialize(context_, is_using_bind_uniform_); | |
2091 } | |
2092 return tile_program_swizzle_.get(); | |
2093 } | |
2094 | |
2095 const GLRenderer::TileProgramSwizzleOpaque* | |
2096 GLRenderer::GetTileProgramSwizzleOpaque() { | |
2097 if (!tile_program_swizzle_opaque_) | |
2098 tile_program_swizzle_opaque_ = | |
2099 make_scoped_ptr(new TileProgramSwizzleOpaque(context_)); | |
2100 if (!tile_program_swizzle_opaque_->initialized()) { | |
2101 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize"); | |
2102 tile_program_swizzle_opaque_->Initialize(context_, is_using_bind_uniform_); | |
2103 } | |
2104 return tile_program_swizzle_opaque_.get(); | |
2105 } | |
2106 | |
2107 const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA() { | |
2108 if (!tile_program_swizzle_aa_) | |
2109 tile_program_swizzle_aa_ = | |
2110 make_scoped_ptr(new TileProgramSwizzleAA(context_)); | |
2111 if (!tile_program_swizzle_aa_->initialized()) { | |
2112 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize"); | |
2113 tile_program_swizzle_aa_->Initialize(context_, is_using_bind_uniform_); | |
2114 } | |
2115 return tile_program_swizzle_aa_.get(); | |
2116 } | |
2117 | |
2118 const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram() { | |
2119 if (!texture_program_) | |
2120 texture_program_ = make_scoped_ptr(new TextureProgram(context_)); | |
2121 if (!texture_program_->initialized()) { | |
2122 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); | |
2123 texture_program_->Initialize(context_, is_using_bind_uniform_); | |
2124 } | |
2125 return texture_program_.get(); | |
2126 } | |
2127 | |
2128 const GLRenderer::TextureProgramFlip* GLRenderer::GetTextureProgramFlip() { | |
2129 if (!texture_program_flip_) | |
2130 texture_program_flip_ = make_scoped_ptr(new TextureProgramFlip(context_)); | |
2131 if (!texture_program_flip_->initialized()) { | |
2132 TRACE_EVENT0("cc", "GLRenderer::textureProgramFlip::initialize"); | |
2133 texture_program_flip_->Initialize(context_, is_using_bind_uniform_); | |
2134 } | |
2135 return texture_program_flip_.get(); | |
2136 } | |
2137 | |
2138 const GLRenderer::TextureIOSurfaceProgram* | |
2139 GLRenderer::GetTextureIOSurfaceProgram() { | |
2140 if (!texture_io_surface_program_) | |
2141 texture_io_surface_program_ = | |
2142 make_scoped_ptr(new TextureIOSurfaceProgram(context_)); | |
2143 if (!texture_io_surface_program_->initialized()) { | |
2144 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize"); | |
2145 texture_io_surface_program_->Initialize(context_, is_using_bind_uniform_); | |
2146 } | |
2147 return texture_io_surface_program_.get(); | |
2148 } | |
2149 | |
2150 const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram() { | |
2151 if (!video_yuv_program_) | |
2152 video_yuv_program_ = make_scoped_ptr(new VideoYUVProgram(context_)); | |
2153 if (!video_yuv_program_->initialized()) { | |
2154 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize"); | |
2155 video_yuv_program_->Initialize(context_, is_using_bind_uniform_); | |
2156 } | |
2157 return video_yuv_program_.get(); | |
2158 } | |
2159 | |
2160 const GLRenderer::VideoStreamTextureProgram* | |
2161 GLRenderer::GetVideoStreamTextureProgram() { | |
2162 if (!Capabilities().using_egl_image) | |
2163 return NULL; | |
2164 if (!video_stream_texture_program_) | |
2165 video_stream_texture_program_ = | |
2166 make_scoped_ptr(new VideoStreamTextureProgram(context_)); | |
2167 if (!video_stream_texture_program_->initialized()) { | |
2168 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize"); | |
2169 video_stream_texture_program_->Initialize(context_, is_using_bind_uniform_); | |
2170 } | |
2171 return video_stream_texture_program_.get(); | |
2172 } | |
2173 | |
2174 void GLRenderer::CleanupSharedObjects() { | |
2175 MakeContextCurrent(); | |
2176 | |
2177 shared_geometry_.reset(); | |
2178 | |
2179 if (tile_program_) | |
2180 tile_program_->Cleanup(context_); | |
2181 if (tile_program_opaque_) | |
2182 tile_program_opaque_->Cleanup(context_); | |
2183 if (tile_program_swizzle_) | |
2184 tile_program_swizzle_->Cleanup(context_); | |
2185 if (tile_program_swizzle_opaque_) | |
2186 tile_program_swizzle_opaque_->Cleanup(context_); | |
2187 if (tile_program_aa_) | |
2188 tile_program_aa_->Cleanup(context_); | |
2189 if (tile_program_swizzle_aa_) | |
2190 tile_program_swizzle_aa_->Cleanup(context_); | |
2191 if (tile_checkerboard_program_) | |
2192 tile_checkerboard_program_->Cleanup(context_); | |
2193 | |
2194 if (render_pass_mask_program_) | |
2195 render_pass_mask_program_->Cleanup(context_); | |
2196 if (render_pass_program_) | |
2197 render_pass_program_->Cleanup(context_); | |
2198 if (render_pass_mask_program_aa_) | |
2199 render_pass_mask_program_aa_->Cleanup(context_); | |
2200 if (render_pass_program_aa_) | |
2201 render_pass_program_aa_->Cleanup(context_); | |
2202 | |
2203 if (texture_program_) | |
2204 texture_program_->Cleanup(context_); | |
2205 if (texture_program_flip_) | |
2206 texture_program_flip_->Cleanup(context_); | |
2207 if (texture_io_surface_program_) | |
2208 texture_io_surface_program_->Cleanup(context_); | |
2209 | |
2210 if (video_yuv_program_) | |
2211 video_yuv_program_->Cleanup(context_); | |
2212 if (video_stream_texture_program_) | |
2213 video_stream_texture_program_->Cleanup(context_); | |
2214 | |
2215 if (debug_border_program_) | |
2216 debug_border_program_->Cleanup(context_); | |
2217 if (solid_color_program_) | |
2218 solid_color_program_->Cleanup(context_); | |
2219 if (solid_color_program_aa_) | |
2220 solid_color_program_aa_->Cleanup(context_); | |
2221 | |
2222 if (offscreen_framebuffer_id_) | |
2223 GLC(context_, context_->deleteFramebuffer(offscreen_framebuffer_id_)); | |
2224 | |
2225 ReleaseRenderPassTextures(); | |
2226 } | |
2227 | |
2228 bool GLRenderer::IsContextLost() { | |
2229 return (context_->getGraphicsResetStatusARB() != GL_NO_ERROR); | |
2230 } | |
2231 | |
2232 } // namespace cc | |
OLD | NEW |