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/output/gl_renderer.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 #include <set> | |
10 #include <string> | |
11 #include <vector> | |
12 | |
13 #include "base/logging.h" | |
14 #include "base/memory/scoped_ptr.h" | |
15 #include "base/strings/string_split.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/strings/stringprintf.h" | |
18 #include "build/build_config.h" | |
19 #include "base/trace_event/trace_event.h" | |
20 #include "cc/base/math_util.h" | |
21 #include "cc/output/compositor_frame.h" | |
22 #include "cc/output/compositor_frame_metadata.h" | |
23 #include "cc/output/context_provider.h" | |
24 #include "cc/output/copy_output_request.h" | |
25 #include "cc/output/dynamic_geometry_binding.h" | |
26 #include "cc/output/gl_frame_data.h" | |
27 #include "cc/output/output_surface.h" | |
28 #include "cc/output/render_surface_filters.h" | |
29 #include "cc/output/static_geometry_binding.h" | |
30 #include "cc/quads/draw_polygon.h" | |
31 #include "cc/quads/render_pass.h" | |
32 #include "cc/quads/stream_video_draw_quad.h" | |
33 #include "cc/quads/texture_draw_quad.h" | |
34 #include "cc/resources/layer_quad.h" | |
35 #include "cc/resources/scoped_resource.h" | |
36 #include "cc/resources/texture_mailbox_deleter.h" | |
37 #include "gpu/GLES2/gl2extchromium.h" | |
38 #include "gpu/command_buffer/client/context_support.h" | |
39 #include "gpu/command_buffer/client/gles2_interface.h" | |
40 #include "gpu/command_buffer/common/gpu_memory_allocation.h" | |
41 #include "third_party/skia/include/core/SkBitmap.h" | |
42 #include "third_party/skia/include/core/SkColor.h" | |
43 #include "third_party/skia/include/core/SkColorFilter.h" | |
44 #include "third_party/skia/include/core/SkImage.h" | |
45 #include "third_party/skia/include/core/SkSurface.h" | |
46 #include "third_party/skia/include/gpu/GrContext.h" | |
47 #include "third_party/skia/include/gpu/GrTexture.h" | |
48 #include "third_party/skia/include/gpu/SkGrTexturePixelRef.h" | |
49 #include "third_party/skia/include/gpu/gl/GrGLInterface.h" | |
50 #include "ui/gfx/geometry/quad_f.h" | |
51 #include "ui/gfx/geometry/rect_conversions.h" | |
52 | |
53 using gpu::gles2::GLES2Interface; | |
54 | |
55 namespace cc { | |
56 namespace { | |
57 | |
58 bool NeedsIOSurfaceReadbackWorkaround() { | |
59 #if defined(OS_MACOSX) | |
60 // This isn't strictly required in DumpRenderTree-mode when Mesa is used, | |
61 // but it doesn't seem to hurt. | |
62 return true; | |
63 #else | |
64 return false; | |
65 #endif | |
66 } | |
67 | |
68 Float4 UVTransform(const TextureDrawQuad* quad) { | |
69 gfx::PointF uv0 = quad->uv_top_left; | |
70 gfx::PointF uv1 = quad->uv_bottom_right; | |
71 Float4 xform = {{uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y()}}; | |
72 if (quad->flipped) { | |
73 xform.data[1] = 1.0f - xform.data[1]; | |
74 xform.data[3] = -xform.data[3]; | |
75 } | |
76 return xform; | |
77 } | |
78 | |
79 Float4 PremultipliedColor(SkColor color) { | |
80 const float factor = 1.0f / 255.0f; | |
81 const float alpha = SkColorGetA(color) * factor; | |
82 | |
83 Float4 result = { | |
84 {SkColorGetR(color) * factor * alpha, SkColorGetG(color) * factor * alpha, | |
85 SkColorGetB(color) * factor * alpha, alpha}}; | |
86 return result; | |
87 } | |
88 | |
89 SamplerType SamplerTypeFromTextureTarget(GLenum target) { | |
90 switch (target) { | |
91 case GL_TEXTURE_2D: | |
92 return SAMPLER_TYPE_2D; | |
93 case GL_TEXTURE_RECTANGLE_ARB: | |
94 return SAMPLER_TYPE_2D_RECT; | |
95 case GL_TEXTURE_EXTERNAL_OES: | |
96 return SAMPLER_TYPE_EXTERNAL_OES; | |
97 default: | |
98 NOTREACHED(); | |
99 return SAMPLER_TYPE_2D; | |
100 } | |
101 } | |
102 | |
103 BlendMode BlendModeFromSkXfermode(SkXfermode::Mode mode) { | |
104 switch (mode) { | |
105 case SkXfermode::kSrcOver_Mode: | |
106 return BLEND_MODE_NORMAL; | |
107 case SkXfermode::kScreen_Mode: | |
108 return BLEND_MODE_SCREEN; | |
109 case SkXfermode::kOverlay_Mode: | |
110 return BLEND_MODE_OVERLAY; | |
111 case SkXfermode::kDarken_Mode: | |
112 return BLEND_MODE_DARKEN; | |
113 case SkXfermode::kLighten_Mode: | |
114 return BLEND_MODE_LIGHTEN; | |
115 case SkXfermode::kColorDodge_Mode: | |
116 return BLEND_MODE_COLOR_DODGE; | |
117 case SkXfermode::kColorBurn_Mode: | |
118 return BLEND_MODE_COLOR_BURN; | |
119 case SkXfermode::kHardLight_Mode: | |
120 return BLEND_MODE_HARD_LIGHT; | |
121 case SkXfermode::kSoftLight_Mode: | |
122 return BLEND_MODE_SOFT_LIGHT; | |
123 case SkXfermode::kDifference_Mode: | |
124 return BLEND_MODE_DIFFERENCE; | |
125 case SkXfermode::kExclusion_Mode: | |
126 return BLEND_MODE_EXCLUSION; | |
127 case SkXfermode::kMultiply_Mode: | |
128 return BLEND_MODE_MULTIPLY; | |
129 case SkXfermode::kHue_Mode: | |
130 return BLEND_MODE_HUE; | |
131 case SkXfermode::kSaturation_Mode: | |
132 return BLEND_MODE_SATURATION; | |
133 case SkXfermode::kColor_Mode: | |
134 return BLEND_MODE_COLOR; | |
135 case SkXfermode::kLuminosity_Mode: | |
136 return BLEND_MODE_LUMINOSITY; | |
137 default: | |
138 NOTREACHED(); | |
139 return BLEND_MODE_NONE; | |
140 } | |
141 } | |
142 | |
143 // Smallest unit that impact anti-aliasing output. We use this to | |
144 // determine when anti-aliasing is unnecessary. | |
145 const float kAntiAliasingEpsilon = 1.0f / 1024.0f; | |
146 | |
147 // Block or crash if the number of pending sync queries reach this high as | |
148 // something is seriously wrong on the service side if this happens. | |
149 const size_t kMaxPendingSyncQueries = 16; | |
150 | |
151 } // anonymous namespace | |
152 | |
153 static GLint GetActiveTextureUnit(GLES2Interface* gl) { | |
154 GLint active_unit = 0; | |
155 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); | |
156 return active_unit; | |
157 } | |
158 | |
159 struct GLRenderer::PendingAsyncReadPixels { | |
160 PendingAsyncReadPixels() : buffer(0) {} | |
161 | |
162 scoped_ptr<CopyOutputRequest> copy_request; | |
163 base::CancelableClosure finished_read_pixels_callback; | |
164 unsigned buffer; | |
165 | |
166 private: | |
167 DISALLOW_COPY_AND_ASSIGN(PendingAsyncReadPixels); | |
168 }; | |
169 | |
170 class GLRenderer::SyncQuery { | |
171 public: | |
172 explicit SyncQuery(gpu::gles2::GLES2Interface* gl) | |
173 : gl_(gl), query_id_(0u), is_pending_(false), weak_ptr_factory_(this) { | |
174 gl_->GenQueriesEXT(1, &query_id_); | |
175 } | |
176 virtual ~SyncQuery() { gl_->DeleteQueriesEXT(1, &query_id_); } | |
177 | |
178 scoped_refptr<ResourceProvider::Fence> Begin() { | |
179 DCHECK(!IsPending()); | |
180 // Invalidate weak pointer held by old fence. | |
181 weak_ptr_factory_.InvalidateWeakPtrs(); | |
182 // Note: In case the set of drawing commands issued before End() do not | |
183 // depend on the query, defer BeginQueryEXT call until Set() is called and | |
184 // query is required. | |
185 return make_scoped_refptr<ResourceProvider::Fence>( | |
186 new Fence(weak_ptr_factory_.GetWeakPtr())); | |
187 } | |
188 | |
189 void Set() { | |
190 if (is_pending_) | |
191 return; | |
192 | |
193 // Note: BeginQueryEXT on GL_COMMANDS_COMPLETED_CHROMIUM is effectively a | |
194 // noop relative to GL, so it doesn't matter where it happens but we still | |
195 // make sure to issue this command when Set() is called (prior to issuing | |
196 // any drawing commands that depend on query), in case some future extension | |
197 // can take advantage of this. | |
198 gl_->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query_id_); | |
199 is_pending_ = true; | |
200 } | |
201 | |
202 void End() { | |
203 if (!is_pending_) | |
204 return; | |
205 | |
206 gl_->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); | |
207 } | |
208 | |
209 bool IsPending() { | |
210 if (!is_pending_) | |
211 return false; | |
212 | |
213 unsigned result_available = 1; | |
214 gl_->GetQueryObjectuivEXT( | |
215 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &result_available); | |
216 is_pending_ = !result_available; | |
217 return is_pending_; | |
218 } | |
219 | |
220 void Wait() { | |
221 if (!is_pending_) | |
222 return; | |
223 | |
224 unsigned result = 0; | |
225 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result); | |
226 is_pending_ = false; | |
227 } | |
228 | |
229 private: | |
230 class Fence : public ResourceProvider::Fence { | |
231 public: | |
232 explicit Fence(base::WeakPtr<GLRenderer::SyncQuery> query) | |
233 : query_(query) {} | |
234 | |
235 // Overridden from ResourceProvider::Fence: | |
236 void Set() override { | |
237 DCHECK(query_); | |
238 query_->Set(); | |
239 } | |
240 bool HasPassed() override { return !query_ || !query_->IsPending(); } | |
241 void Wait() override { | |
242 if (query_) | |
243 query_->Wait(); | |
244 } | |
245 | |
246 private: | |
247 ~Fence() override {} | |
248 | |
249 base::WeakPtr<SyncQuery> query_; | |
250 | |
251 DISALLOW_COPY_AND_ASSIGN(Fence); | |
252 }; | |
253 | |
254 gpu::gles2::GLES2Interface* gl_; | |
255 unsigned query_id_; | |
256 bool is_pending_; | |
257 base::WeakPtrFactory<SyncQuery> weak_ptr_factory_; | |
258 | |
259 DISALLOW_COPY_AND_ASSIGN(SyncQuery); | |
260 }; | |
261 | |
262 scoped_ptr<GLRenderer> GLRenderer::Create( | |
263 RendererClient* client, | |
264 const RendererSettings* settings, | |
265 OutputSurface* output_surface, | |
266 ResourceProvider* resource_provider, | |
267 TextureMailboxDeleter* texture_mailbox_deleter, | |
268 int highp_threshold_min) { | |
269 return make_scoped_ptr(new GLRenderer(client, | |
270 settings, | |
271 output_surface, | |
272 resource_provider, | |
273 texture_mailbox_deleter, | |
274 highp_threshold_min)); | |
275 } | |
276 | |
277 GLRenderer::GLRenderer(RendererClient* client, | |
278 const RendererSettings* settings, | |
279 OutputSurface* output_surface, | |
280 ResourceProvider* resource_provider, | |
281 TextureMailboxDeleter* texture_mailbox_deleter, | |
282 int highp_threshold_min) | |
283 : DirectRenderer(client, settings, output_surface, resource_provider), | |
284 offscreen_framebuffer_id_(0), | |
285 shared_geometry_quad_(QuadVertexRect()), | |
286 gl_(output_surface->context_provider()->ContextGL()), | |
287 context_support_(output_surface->context_provider()->ContextSupport()), | |
288 texture_mailbox_deleter_(texture_mailbox_deleter), | |
289 is_backbuffer_discarded_(false), | |
290 is_scissor_enabled_(false), | |
291 scissor_rect_needs_reset_(true), | |
292 stencil_shadow_(false), | |
293 blend_shadow_(false), | |
294 highp_threshold_min_(highp_threshold_min), | |
295 highp_threshold_cache_(0), | |
296 use_sync_query_(false), | |
297 on_demand_tile_raster_resource_id_(0), | |
298 bound_geometry_(NO_BINDING) { | |
299 DCHECK(gl_); | |
300 DCHECK(context_support_); | |
301 | |
302 ContextProvider::Capabilities context_caps = | |
303 output_surface_->context_provider()->ContextCapabilities(); | |
304 | |
305 capabilities_.using_partial_swap = | |
306 settings_->partial_swap_enabled && context_caps.gpu.post_sub_buffer; | |
307 | |
308 DCHECK(!context_caps.gpu.iosurface || context_caps.gpu.texture_rectangle); | |
309 | |
310 capabilities_.using_egl_image = context_caps.gpu.egl_image_external; | |
311 | |
312 capabilities_.max_texture_size = resource_provider_->max_texture_size(); | |
313 capabilities_.best_texture_format = resource_provider_->best_texture_format(); | |
314 | |
315 // The updater can access textures while the GLRenderer is using them. | |
316 capabilities_.allow_partial_texture_updates = true; | |
317 | |
318 capabilities_.using_image = context_caps.gpu.image; | |
319 | |
320 capabilities_.using_discard_framebuffer = | |
321 context_caps.gpu.discard_framebuffer; | |
322 | |
323 capabilities_.allow_rasterize_on_demand = true; | |
324 | |
325 use_sync_query_ = context_caps.gpu.sync_query; | |
326 use_blend_equation_advanced_ = context_caps.gpu.blend_equation_advanced; | |
327 use_blend_equation_advanced_coherent_ = | |
328 context_caps.gpu.blend_equation_advanced_coherent; | |
329 | |
330 InitializeSharedObjects(); | |
331 } | |
332 | |
333 GLRenderer::~GLRenderer() { | |
334 while (!pending_async_read_pixels_.empty()) { | |
335 PendingAsyncReadPixels* pending_read = pending_async_read_pixels_.back(); | |
336 pending_read->finished_read_pixels_callback.Cancel(); | |
337 pending_async_read_pixels_.pop_back(); | |
338 } | |
339 | |
340 in_use_overlay_resources_.clear(); | |
341 | |
342 CleanupSharedObjects(); | |
343 } | |
344 | |
345 const RendererCapabilitiesImpl& GLRenderer::Capabilities() const { | |
346 return capabilities_; | |
347 } | |
348 | |
349 void GLRenderer::DebugGLCall(GLES2Interface* gl, | |
350 const char* command, | |
351 const char* file, | |
352 int line) { | |
353 GLuint error = gl->GetError(); | |
354 if (error != GL_NO_ERROR) | |
355 LOG(ERROR) << "GL command failed: File: " << file << "\n\tLine " << line | |
356 << "\n\tcommand: " << command << ", error " | |
357 << static_cast<int>(error) << "\n"; | |
358 } | |
359 | |
360 void GLRenderer::DidChangeVisibility() { | |
361 EnforceMemoryPolicy(); | |
362 | |
363 context_support_->SetSurfaceVisible(visible()); | |
364 } | |
365 | |
366 void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); } | |
367 | |
368 void GLRenderer::DiscardPixels() { | |
369 if (!capabilities_.using_discard_framebuffer) | |
370 return; | |
371 bool using_default_framebuffer = | |
372 !current_framebuffer_lock_ && | |
373 output_surface_->capabilities().uses_default_gl_framebuffer; | |
374 GLenum attachments[] = {static_cast<GLenum>( | |
375 using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)}; | |
376 gl_->DiscardFramebufferEXT( | |
377 GL_FRAMEBUFFER, arraysize(attachments), attachments); | |
378 } | |
379 | |
380 void GLRenderer::PrepareSurfaceForPass( | |
381 DrawingFrame* frame, | |
382 SurfaceInitializationMode initialization_mode, | |
383 const gfx::Rect& render_pass_scissor) { | |
384 switch (initialization_mode) { | |
385 case SURFACE_INITIALIZATION_MODE_PRESERVE: | |
386 EnsureScissorTestDisabled(); | |
387 return; | |
388 case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR: | |
389 EnsureScissorTestDisabled(); | |
390 DiscardPixels(); | |
391 ClearFramebuffer(frame); | |
392 break; | |
393 case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR: | |
394 SetScissorTestRect(render_pass_scissor); | |
395 ClearFramebuffer(frame); | |
396 break; | |
397 } | |
398 } | |
399 | |
400 void GLRenderer::ClearFramebuffer(DrawingFrame* frame) { | |
401 // On DEBUG builds, opaque render passes are cleared to blue to easily see | |
402 // regions that were not drawn on the screen. | |
403 if (frame->current_render_pass->has_transparent_background) | |
404 GLC(gl_, gl_->ClearColor(0, 0, 0, 0)); | |
405 else | |
406 GLC(gl_, gl_->ClearColor(0, 0, 1, 1)); | |
407 | |
408 bool always_clear = false; | |
409 #ifndef NDEBUG | |
410 always_clear = true; | |
411 #endif | |
412 if (always_clear || frame->current_render_pass->has_transparent_background) { | |
413 GLbitfield clear_bits = GL_COLOR_BUFFER_BIT; | |
414 if (always_clear) | |
415 clear_bits |= GL_STENCIL_BUFFER_BIT; | |
416 gl_->Clear(clear_bits); | |
417 } | |
418 } | |
419 | |
420 static ResourceProvider::ResourceId WaitOnResourceSyncPoints( | |
421 ResourceProvider* resource_provider, | |
422 ResourceProvider::ResourceId resource_id) { | |
423 resource_provider->WaitSyncPointIfNeeded(resource_id); | |
424 return resource_id; | |
425 } | |
426 | |
427 void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) { | |
428 TRACE_EVENT0("cc", "GLRenderer::BeginDrawingFrame"); | |
429 | |
430 scoped_refptr<ResourceProvider::Fence> read_lock_fence; | |
431 if (use_sync_query_) { | |
432 // Block until oldest sync query has passed if the number of pending queries | |
433 // ever reach kMaxPendingSyncQueries. | |
434 if (pending_sync_queries_.size() >= kMaxPendingSyncQueries) { | |
435 LOG(ERROR) << "Reached limit of pending sync queries."; | |
436 | |
437 pending_sync_queries_.front()->Wait(); | |
438 DCHECK(!pending_sync_queries_.front()->IsPending()); | |
439 } | |
440 | |
441 while (!pending_sync_queries_.empty()) { | |
442 if (pending_sync_queries_.front()->IsPending()) | |
443 break; | |
444 | |
445 available_sync_queries_.push_back(pending_sync_queries_.take_front()); | |
446 } | |
447 | |
448 current_sync_query_ = available_sync_queries_.empty() | |
449 ? make_scoped_ptr(new SyncQuery(gl_)) | |
450 : available_sync_queries_.take_front(); | |
451 | |
452 read_lock_fence = current_sync_query_->Begin(); | |
453 } else { | |
454 read_lock_fence = | |
455 make_scoped_refptr(new ResourceProvider::SynchronousFence(gl_)); | |
456 } | |
457 resource_provider_->SetReadLockFence(read_lock_fence.get()); | |
458 | |
459 // Insert WaitSyncPointCHROMIUM on quad resources prior to drawing the frame, | |
460 // so that drawing can proceed without GL context switching interruptions. | |
461 DrawQuad::ResourceIteratorCallback wait_on_resource_syncpoints_callback = | |
462 base::Bind(&WaitOnResourceSyncPoints, resource_provider_); | |
463 | |
464 for (const auto& pass : *frame->render_passes_in_draw_order) { | |
465 for (const auto& quad : pass->quad_list) | |
466 quad->IterateResources(wait_on_resource_syncpoints_callback); | |
467 } | |
468 | |
469 // TODO(enne): Do we need to reinitialize all of this state per frame? | |
470 ReinitializeGLState(); | |
471 } | |
472 | |
473 void GLRenderer::DoNoOp() { | |
474 GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, 0)); | |
475 GLC(gl_, gl_->Flush()); | |
476 } | |
477 | |
478 void GLRenderer::DoDrawQuad(DrawingFrame* frame, | |
479 const DrawQuad* quad, | |
480 const gfx::QuadF* clip_region) { | |
481 DCHECK(quad->rect.Contains(quad->visible_rect)); | |
482 if (quad->material != DrawQuad::TEXTURE_CONTENT) { | |
483 FlushTextureQuadCache(SHARED_BINDING); | |
484 } | |
485 | |
486 switch (quad->material) { | |
487 case DrawQuad::INVALID: | |
488 case DrawQuad::UNUSED_SPACE_FOR_PICTURE_CONTENT: | |
489 NOTREACHED(); | |
490 break; | |
491 case DrawQuad::CHECKERBOARD: | |
492 DrawCheckerboardQuad(frame, CheckerboardDrawQuad::MaterialCast(quad), | |
493 clip_region); | |
494 break; | |
495 case DrawQuad::DEBUG_BORDER: | |
496 DrawDebugBorderQuad(frame, DebugBorderDrawQuad::MaterialCast(quad)); | |
497 break; | |
498 case DrawQuad::IO_SURFACE_CONTENT: | |
499 DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad), | |
500 clip_region); | |
501 break; | |
502 case DrawQuad::RENDER_PASS: | |
503 DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad), | |
504 clip_region); | |
505 break; | |
506 case DrawQuad::SOLID_COLOR: | |
507 DrawSolidColorQuad(frame, SolidColorDrawQuad::MaterialCast(quad), | |
508 clip_region); | |
509 break; | |
510 case DrawQuad::STREAM_VIDEO_CONTENT: | |
511 DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad), | |
512 clip_region); | |
513 break; | |
514 case DrawQuad::SURFACE_CONTENT: | |
515 // Surface content should be fully resolved to other quad types before | |
516 // reaching a direct renderer. | |
517 NOTREACHED(); | |
518 break; | |
519 case DrawQuad::TEXTURE_CONTENT: | |
520 EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad), | |
521 clip_region); | |
522 break; | |
523 case DrawQuad::TILED_CONTENT: | |
524 DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad), clip_region); | |
525 break; | |
526 case DrawQuad::YUV_VIDEO_CONTENT: | |
527 DrawYUVVideoQuad(frame, YUVVideoDrawQuad::MaterialCast(quad), | |
528 clip_region); | |
529 break; | |
530 } | |
531 } | |
532 | |
533 void GLRenderer::DrawCheckerboardQuad(const DrawingFrame* frame, | |
534 const CheckerboardDrawQuad* quad, | |
535 const gfx::QuadF* clip_region) { | |
536 // TODO(enne) For now since checkerboards shouldn't be part of a 3D | |
537 // context, clipping regions aren't supported so we skip drawing them | |
538 // if this becomes the case. | |
539 if (clip_region) { | |
540 return; | |
541 } | |
542 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
543 | |
544 const TileCheckerboardProgram* program = GetTileCheckerboardProgram(); | |
545 DCHECK(program && (program->initialized() || IsContextLost())); | |
546 SetUseProgram(program->program()); | |
547 | |
548 SkColor color = quad->color; | |
549 GLC(gl_, | |
550 gl_->Uniform4f(program->fragment_shader().color_location(), | |
551 SkColorGetR(color) * (1.0f / 255.0f), | |
552 SkColorGetG(color) * (1.0f / 255.0f), | |
553 SkColorGetB(color) * (1.0f / 255.0f), | |
554 1)); | |
555 | |
556 const int kCheckerboardWidth = 16; | |
557 float frequency = 1.0f / kCheckerboardWidth; | |
558 | |
559 gfx::Rect tile_rect = quad->rect; | |
560 float tex_offset_x = | |
561 static_cast<int>(tile_rect.x() / quad->scale) % kCheckerboardWidth; | |
562 float tex_offset_y = | |
563 static_cast<int>(tile_rect.y() / quad->scale) % kCheckerboardWidth; | |
564 float tex_scale_x = tile_rect.width() / quad->scale; | |
565 float tex_scale_y = tile_rect.height() / quad->scale; | |
566 GLC(gl_, | |
567 gl_->Uniform4f(program->fragment_shader().tex_transform_location(), | |
568 tex_offset_x, | |
569 tex_offset_y, | |
570 tex_scale_x, | |
571 tex_scale_y)); | |
572 | |
573 GLC(gl_, | |
574 gl_->Uniform1f(program->fragment_shader().frequency_location(), | |
575 frequency)); | |
576 | |
577 SetShaderOpacity(quad->opacity(), | |
578 program->fragment_shader().alpha_location()); | |
579 DrawQuadGeometry(frame, | |
580 quad->quadTransform(), | |
581 quad->rect, | |
582 program->vertex_shader().matrix_location()); | |
583 } | |
584 | |
585 // This function does not handle 3D sorting right now, since the debug border | |
586 // quads are just drawn as their original quads and not in split pieces. This | |
587 // results in some debug border quads drawing over foreground quads. | |
588 void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame, | |
589 const DebugBorderDrawQuad* quad) { | |
590 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
591 | |
592 static float gl_matrix[16]; | |
593 const DebugBorderProgram* program = GetDebugBorderProgram(); | |
594 DCHECK(program && (program->initialized() || IsContextLost())); | |
595 SetUseProgram(program->program()); | |
596 | |
597 // Use the full quad_rect for debug quads to not move the edges based on | |
598 // partial swaps. | |
599 gfx::Rect layer_rect = quad->rect; | |
600 gfx::Transform render_matrix; | |
601 QuadRectTransform(&render_matrix, quad->quadTransform(), layer_rect); | |
602 GLRenderer::ToGLMatrix(&gl_matrix[0], | |
603 frame->projection_matrix * render_matrix); | |
604 GLC(gl_, | |
605 gl_->UniformMatrix4fv( | |
606 program->vertex_shader().matrix_location(), 1, false, &gl_matrix[0])); | |
607 | |
608 SkColor color = quad->color; | |
609 float alpha = SkColorGetA(color) * (1.0f / 255.0f); | |
610 | |
611 GLC(gl_, | |
612 gl_->Uniform4f(program->fragment_shader().color_location(), | |
613 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, | |
614 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, | |
615 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, | |
616 alpha)); | |
617 | |
618 GLC(gl_, gl_->LineWidth(quad->width)); | |
619 | |
620 // The indices for the line are stored in the same array as the triangle | |
621 // indices. | |
622 GLC(gl_, gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0)); | |
623 } | |
624 | |
625 bool GLRenderer::CanApplyBlendModeUsingBlendFunc(SkXfermode::Mode blend_mode) { | |
626 return use_blend_equation_advanced_ || | |
627 blend_mode == SkXfermode::kScreen_Mode || | |
628 blend_mode == SkXfermode::kSrcOver_Mode; | |
629 } | |
630 | |
631 void GLRenderer::ApplyBlendModeUsingBlendFunc(SkXfermode::Mode blend_mode) { | |
632 DCHECK(CanApplyBlendModeUsingBlendFunc(blend_mode)); | |
633 | |
634 // Any modes set here must be reset in RestoreBlendFuncToDefault | |
635 if (use_blend_equation_advanced_) { | |
636 GLenum equation = GL_FUNC_ADD; | |
637 | |
638 switch (blend_mode) { | |
639 case SkXfermode::kScreen_Mode: | |
640 equation = GL_SCREEN_KHR; | |
641 break; | |
642 case SkXfermode::kOverlay_Mode: | |
643 equation = GL_OVERLAY_KHR; | |
644 break; | |
645 case SkXfermode::kDarken_Mode: | |
646 equation = GL_DARKEN_KHR; | |
647 break; | |
648 case SkXfermode::kLighten_Mode: | |
649 equation = GL_LIGHTEN_KHR; | |
650 break; | |
651 case SkXfermode::kColorDodge_Mode: | |
652 equation = GL_COLORDODGE_KHR; | |
653 break; | |
654 case SkXfermode::kColorBurn_Mode: | |
655 equation = GL_COLORBURN_KHR; | |
656 break; | |
657 case SkXfermode::kHardLight_Mode: | |
658 equation = GL_HARDLIGHT_KHR; | |
659 break; | |
660 case SkXfermode::kSoftLight_Mode: | |
661 equation = GL_SOFTLIGHT_KHR; | |
662 break; | |
663 case SkXfermode::kDifference_Mode: | |
664 equation = GL_DIFFERENCE_KHR; | |
665 break; | |
666 case SkXfermode::kExclusion_Mode: | |
667 equation = GL_EXCLUSION_KHR; | |
668 break; | |
669 case SkXfermode::kMultiply_Mode: | |
670 equation = GL_MULTIPLY_KHR; | |
671 break; | |
672 case SkXfermode::kHue_Mode: | |
673 equation = GL_HSL_HUE_KHR; | |
674 break; | |
675 case SkXfermode::kSaturation_Mode: | |
676 equation = GL_HSL_SATURATION_KHR; | |
677 break; | |
678 case SkXfermode::kColor_Mode: | |
679 equation = GL_HSL_COLOR_KHR; | |
680 break; | |
681 case SkXfermode::kLuminosity_Mode: | |
682 equation = GL_HSL_LUMINOSITY_KHR; | |
683 break; | |
684 default: | |
685 return; | |
686 } | |
687 | |
688 GLC(gl_, gl_->BlendEquation(equation)); | |
689 } else { | |
690 if (blend_mode == SkXfermode::kScreen_Mode) { | |
691 GLC(gl_, gl_->BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE)); | |
692 } | |
693 } | |
694 } | |
695 | |
696 void GLRenderer::RestoreBlendFuncToDefault(SkXfermode::Mode blend_mode) { | |
697 if (blend_mode == SkXfermode::kSrcOver_Mode) | |
698 return; | |
699 | |
700 if (use_blend_equation_advanced_) { | |
701 GLC(gl_, gl_->BlendEquation(GL_FUNC_ADD)); | |
702 } else { | |
703 GLC(gl_, gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
704 } | |
705 } | |
706 | |
707 // This takes a gfx::Rect and a clip region quad in the same space, | |
708 // and returns a quad with the same proportions in the space -0.5->0.5. | |
709 bool GetScaledRegion(const gfx::Rect& rect, | |
710 const gfx::QuadF* clip, | |
711 gfx::QuadF* scaled_region) { | |
712 if (!clip) | |
713 return false; | |
714 | |
715 gfx::PointF p1(((clip->p1().x() - rect.x()) / rect.width()) - 0.5f, | |
716 ((clip->p1().y() - rect.y()) / rect.height()) - 0.5f); | |
717 gfx::PointF p2(((clip->p2().x() - rect.x()) / rect.width()) - 0.5f, | |
718 ((clip->p2().y() - rect.y()) / rect.height()) - 0.5f); | |
719 gfx::PointF p3(((clip->p3().x() - rect.x()) / rect.width()) - 0.5f, | |
720 ((clip->p3().y() - rect.y()) / rect.height()) - 0.5f); | |
721 gfx::PointF p4(((clip->p4().x() - rect.x()) / rect.width()) - 0.5f, | |
722 ((clip->p4().y() - rect.y()) / rect.height()) - 0.5f); | |
723 *scaled_region = gfx::QuadF(p1, p2, p3, p4); | |
724 return true; | |
725 } | |
726 | |
727 // This takes a gfx::Rect and a clip region quad in the same space, | |
728 // and returns the proportional uv's in the space 0->1. | |
729 bool GetScaledUVs(const gfx::Rect& rect, const gfx::QuadF* clip, float uvs[8]) { | |
730 if (!clip) | |
731 return false; | |
732 | |
733 uvs[0] = ((clip->p1().x() - rect.x()) / rect.width()); | |
734 uvs[1] = ((clip->p1().y() - rect.y()) / rect.height()); | |
735 uvs[2] = ((clip->p2().x() - rect.x()) / rect.width()); | |
736 uvs[3] = ((clip->p2().y() - rect.y()) / rect.height()); | |
737 uvs[4] = ((clip->p3().x() - rect.x()) / rect.width()); | |
738 uvs[5] = ((clip->p3().y() - rect.y()) / rect.height()); | |
739 uvs[6] = ((clip->p4().x() - rect.x()) / rect.width()); | |
740 uvs[7] = ((clip->p4().y() - rect.y()) / rect.height()); | |
741 return true; | |
742 } | |
743 | |
744 gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad( | |
745 DrawingFrame* frame, | |
746 const RenderPassDrawQuad* quad, | |
747 const gfx::Transform& contents_device_transform, | |
748 const gfx::QuadF* clip_region, | |
749 bool use_aa) { | |
750 gfx::QuadF scaled_region; | |
751 if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) { | |
752 scaled_region = SharedGeometryQuad().BoundingBox(); | |
753 } | |
754 | |
755 gfx::Rect backdrop_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect( | |
756 contents_device_transform, scaled_region.BoundingBox())); | |
757 | |
758 if (!backdrop_rect.IsEmpty() && use_aa) { | |
759 const int kOutsetForAntialiasing = 1; | |
760 backdrop_rect.Inset(-kOutsetForAntialiasing, -kOutsetForAntialiasing); | |
761 } | |
762 | |
763 backdrop_rect.Intersect(MoveFromDrawToWindowSpace( | |
764 frame, frame->current_render_pass->output_rect)); | |
765 return backdrop_rect; | |
766 } | |
767 | |
768 scoped_ptr<ScopedResource> GLRenderer::GetBackdropTexture( | |
769 const gfx::Rect& bounding_rect) { | |
770 scoped_ptr<ScopedResource> device_background_texture = | |
771 ScopedResource::Create(resource_provider_); | |
772 // CopyTexImage2D fails when called on a texture having immutable storage. | |
773 device_background_texture->Allocate( | |
774 bounding_rect.size(), ResourceProvider::TEXTURE_HINT_DEFAULT, RGBA_8888); | |
775 { | |
776 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, | |
777 device_background_texture->id()); | |
778 GetFramebufferTexture( | |
779 lock.texture_id(), device_background_texture->format(), bounding_rect); | |
780 } | |
781 return device_background_texture.Pass(); | |
782 } | |
783 | |
784 void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, | |
785 const RenderPassDrawQuad* quad, | |
786 const gfx::QuadF* clip_region) { | |
787 ScopedResource* contents_texture = | |
788 render_pass_textures_.get(quad->render_pass_id); | |
789 if (!contents_texture || !contents_texture->id()) | |
790 return; | |
791 | |
792 gfx::Transform quad_rect_matrix; | |
793 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); | |
794 gfx::Transform contents_device_transform = | |
795 frame->window_matrix * frame->projection_matrix * quad_rect_matrix; | |
796 contents_device_transform.FlattenTo2d(); | |
797 | |
798 // Can only draw surface if device matrix is invertible. | |
799 if (!contents_device_transform.IsInvertible()) | |
800 return; | |
801 | |
802 gfx::QuadF surface_quad = SharedGeometryQuad(); | |
803 float edge[24]; | |
804 bool use_aa = settings_->allow_antialiasing && | |
805 ShouldAntialiasQuad(contents_device_transform, quad, | |
806 settings_->force_antialiasing); | |
807 | |
808 SetupQuadForClippingAndAntialiasing(contents_device_transform, quad, use_aa, | |
809 clip_region, &surface_quad, edge); | |
810 SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode; | |
811 bool use_shaders_for_blending = | |
812 !CanApplyBlendModeUsingBlendFunc(blend_mode) || | |
813 settings_->force_blending_with_shaders; | |
814 | |
815 scoped_ptr<ScopedResource> background_texture; | |
816 skia::RefPtr<SkImage> background_image; | |
817 gfx::Rect background_rect; | |
818 if (use_shaders_for_blending) { | |
819 // Compute a bounding box around the pixels that will be visible through | |
820 // the quad. | |
821 background_rect = GetBackdropBoundingBoxForRenderPassQuad( | |
822 frame, quad, contents_device_transform, clip_region, use_aa); | |
823 | |
824 if (!background_rect.IsEmpty()) { | |
825 // The pixels from the filtered background should completely replace the | |
826 // current pixel values. | |
827 if (blend_enabled()) | |
828 SetBlendEnabled(false); | |
829 | |
830 // Read the pixels in the bounding box into a buffer R. | |
831 // This function allocates a texture, which should contribute to the | |
832 // amount of memory used by render surfaces: | |
833 // LayerTreeHost::CalculateMemoryForRenderSurfaces. | |
834 background_texture = GetBackdropTexture(background_rect); | |
835 } | |
836 | |
837 if (!background_texture) { | |
838 // Something went wrong with reading the backdrop. | |
839 DCHECK(!background_image); | |
840 use_shaders_for_blending = false; | |
841 } else if (background_image) { | |
842 // Reset original background texture if there is not any mask | |
843 if (!quad->mask_resource_id) | |
844 background_texture.reset(); | |
845 } | |
846 } | |
847 // Need original background texture for mask? | |
848 bool mask_for_background = | |
849 background_texture && // Have original background texture | |
850 background_image && // Have filtered background texture | |
851 quad->mask_resource_id; // Have mask texture | |
852 SetBlendEnabled( | |
853 !use_shaders_for_blending && | |
854 (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode))); | |
855 | |
856 // TODO(senorblanco): Cache this value so that we don't have to do it for both | |
857 // the surface and its replica. Apply filters to the contents texture. | |
858 skia::RefPtr<SkImage> filter_image; | |
859 SkScalar color_matrix[20]; | |
860 bool use_color_matrix = false; | |
861 DCHECK(quad->filters.IsEmpty()); | |
862 | |
863 scoped_ptr<ResourceProvider::ScopedSamplerGL> mask_resource_lock; | |
864 unsigned mask_texture_id = 0; | |
865 SamplerType mask_sampler = SAMPLER_TYPE_NA; | |
866 if (quad->mask_resource_id) { | |
867 mask_resource_lock.reset(new ResourceProvider::ScopedSamplerGL( | |
868 resource_provider_, quad->mask_resource_id, GL_TEXTURE1, GL_LINEAR)); | |
869 mask_texture_id = mask_resource_lock->texture_id(); | |
870 mask_sampler = SamplerTypeFromTextureTarget(mask_resource_lock->target()); | |
871 } | |
872 | |
873 scoped_ptr<ResourceProvider::ScopedSamplerGL> contents_resource_lock; | |
874 if (filter_image) { | |
875 GrTexture* texture = filter_image->getTexture(); | |
876 DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); | |
877 gl_->BindTexture(GL_TEXTURE_2D, texture->getTextureHandle()); | |
878 } else { | |
879 contents_resource_lock = | |
880 make_scoped_ptr(new ResourceProvider::ScopedSamplerGL( | |
881 resource_provider_, contents_texture->id(), GL_LINEAR)); | |
882 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), | |
883 contents_resource_lock->target()); | |
884 } | |
885 | |
886 if (!use_shaders_for_blending) { | |
887 if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_) | |
888 GLC(gl_, gl_->BlendBarrierKHR()); | |
889 | |
890 ApplyBlendModeUsingBlendFunc(blend_mode); | |
891 } | |
892 | |
893 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
894 gl_, | |
895 &highp_threshold_cache_, | |
896 highp_threshold_min_, | |
897 quad->shared_quad_state->visible_content_rect.bottom_right()); | |
898 | |
899 ShaderLocations locations; | |
900 | |
901 DCHECK_EQ(background_texture || background_image, use_shaders_for_blending); | |
902 BlendMode shader_blend_mode = use_shaders_for_blending | |
903 ? BlendModeFromSkXfermode(blend_mode) | |
904 : BLEND_MODE_NONE; | |
905 | |
906 if (use_aa && mask_texture_id && !use_color_matrix) { | |
907 const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA( | |
908 tex_coord_precision, mask_sampler, | |
909 shader_blend_mode, mask_for_background); | |
910 SetUseProgram(program->program()); | |
911 program->vertex_shader().FillLocations(&locations); | |
912 program->fragment_shader().FillLocations(&locations); | |
913 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
914 } else if (!use_aa && mask_texture_id && !use_color_matrix) { | |
915 const RenderPassMaskProgram* program = GetRenderPassMaskProgram( | |
916 tex_coord_precision, mask_sampler, | |
917 shader_blend_mode, mask_for_background); | |
918 SetUseProgram(program->program()); | |
919 program->vertex_shader().FillLocations(&locations); | |
920 program->fragment_shader().FillLocations(&locations); | |
921 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
922 } else if (use_aa && !mask_texture_id && !use_color_matrix) { | |
923 const RenderPassProgramAA* program = | |
924 GetRenderPassProgramAA(tex_coord_precision, shader_blend_mode); | |
925 SetUseProgram(program->program()); | |
926 program->vertex_shader().FillLocations(&locations); | |
927 program->fragment_shader().FillLocations(&locations); | |
928 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
929 } else if (use_aa && mask_texture_id && use_color_matrix) { | |
930 const RenderPassMaskColorMatrixProgramAA* program = | |
931 GetRenderPassMaskColorMatrixProgramAA( | |
932 tex_coord_precision, mask_sampler, | |
933 shader_blend_mode, mask_for_background); | |
934 SetUseProgram(program->program()); | |
935 program->vertex_shader().FillLocations(&locations); | |
936 program->fragment_shader().FillLocations(&locations); | |
937 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
938 } else if (use_aa && !mask_texture_id && use_color_matrix) { | |
939 const RenderPassColorMatrixProgramAA* program = | |
940 GetRenderPassColorMatrixProgramAA(tex_coord_precision, | |
941 shader_blend_mode); | |
942 SetUseProgram(program->program()); | |
943 program->vertex_shader().FillLocations(&locations); | |
944 program->fragment_shader().FillLocations(&locations); | |
945 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
946 } else if (!use_aa && mask_texture_id && use_color_matrix) { | |
947 const RenderPassMaskColorMatrixProgram* program = | |
948 GetRenderPassMaskColorMatrixProgram( | |
949 tex_coord_precision, mask_sampler, | |
950 shader_blend_mode, mask_for_background); | |
951 SetUseProgram(program->program()); | |
952 program->vertex_shader().FillLocations(&locations); | |
953 program->fragment_shader().FillLocations(&locations); | |
954 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
955 } else if (!use_aa && !mask_texture_id && use_color_matrix) { | |
956 const RenderPassColorMatrixProgram* program = | |
957 GetRenderPassColorMatrixProgram(tex_coord_precision, shader_blend_mode); | |
958 SetUseProgram(program->program()); | |
959 program->vertex_shader().FillLocations(&locations); | |
960 program->fragment_shader().FillLocations(&locations); | |
961 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
962 } else { | |
963 const RenderPassProgram* program = | |
964 GetRenderPassProgram(tex_coord_precision, shader_blend_mode); | |
965 SetUseProgram(program->program()); | |
966 program->vertex_shader().FillLocations(&locations); | |
967 program->fragment_shader().FillLocations(&locations); | |
968 GLC(gl_, gl_->Uniform1i(locations.sampler, 0)); | |
969 } | |
970 float tex_scale_x = | |
971 quad->rect.width() / static_cast<float>(contents_texture->size().width()); | |
972 float tex_scale_y = quad->rect.height() / | |
973 static_cast<float>(contents_texture->size().height()); | |
974 DCHECK_LE(tex_scale_x, 1.0f); | |
975 DCHECK_LE(tex_scale_y, 1.0f); | |
976 | |
977 DCHECK(locations.tex_transform != -1 || IsContextLost()); | |
978 // Flip the content vertically in the shader, as the RenderPass input | |
979 // texture is already oriented the same way as the framebuffer, but the | |
980 // projection transform does a flip. | |
981 GLC(gl_, | |
982 gl_->Uniform4f(locations.tex_transform, | |
983 0.0f, | |
984 tex_scale_y, | |
985 tex_scale_x, | |
986 -tex_scale_y)); | |
987 | |
988 GLint last_texture_unit = 0; | |
989 if (locations.mask_sampler != -1) { | |
990 DCHECK_NE(locations.mask_tex_coord_scale, 1); | |
991 DCHECK_NE(locations.mask_tex_coord_offset, 1); | |
992 GLC(gl_, gl_->Uniform1i(locations.mask_sampler, 1)); | |
993 | |
994 gfx::RectF mask_uv_rect = quad->MaskUVRect(); | |
995 if (mask_sampler != SAMPLER_TYPE_2D) { | |
996 mask_uv_rect.Scale(quad->mask_texture_size.width(), | |
997 quad->mask_texture_size.height()); | |
998 } | |
999 | |
1000 // Mask textures are oriented vertically flipped relative to the framebuffer | |
1001 // and the RenderPass contents texture, so we flip the tex coords from the | |
1002 // RenderPass texture to find the mask texture coords. | |
1003 GLC(gl_, | |
1004 gl_->Uniform2f(locations.mask_tex_coord_offset, | |
1005 mask_uv_rect.x(), | |
1006 mask_uv_rect.bottom())); | |
1007 GLC(gl_, | |
1008 gl_->Uniform2f(locations.mask_tex_coord_scale, | |
1009 mask_uv_rect.width() / tex_scale_x, | |
1010 -mask_uv_rect.height() / tex_scale_y)); | |
1011 | |
1012 last_texture_unit = 1; | |
1013 } | |
1014 | |
1015 if (locations.edge != -1) | |
1016 GLC(gl_, gl_->Uniform3fv(locations.edge, 8, edge)); | |
1017 | |
1018 if (locations.viewport != -1) { | |
1019 float viewport[4] = {static_cast<float>(viewport_.x()), | |
1020 static_cast<float>(viewport_.y()), | |
1021 static_cast<float>(viewport_.width()), | |
1022 static_cast<float>(viewport_.height()), }; | |
1023 GLC(gl_, gl_->Uniform4fv(locations.viewport, 1, viewport)); | |
1024 } | |
1025 | |
1026 if (locations.color_matrix != -1) { | |
1027 float matrix[16]; | |
1028 for (int i = 0; i < 4; ++i) { | |
1029 for (int j = 0; j < 4; ++j) | |
1030 matrix[i * 4 + j] = SkScalarToFloat(color_matrix[j * 5 + i]); | |
1031 } | |
1032 GLC(gl_, | |
1033 gl_->UniformMatrix4fv(locations.color_matrix, 1, false, matrix)); | |
1034 } | |
1035 static const float kScale = 1.0f / 255.0f; | |
1036 if (locations.color_offset != -1) { | |
1037 float offset[4]; | |
1038 for (int i = 0; i < 4; ++i) | |
1039 offset[i] = SkScalarToFloat(color_matrix[i * 5 + 4]) * kScale; | |
1040 | |
1041 GLC(gl_, gl_->Uniform4fv(locations.color_offset, 1, offset)); | |
1042 } | |
1043 | |
1044 scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_background_sampler_lock; | |
1045 if (locations.backdrop != -1) { | |
1046 DCHECK(background_texture || background_image); | |
1047 DCHECK_NE(locations.backdrop, 0); | |
1048 DCHECK_NE(locations.backdrop_rect, 0); | |
1049 | |
1050 GLC(gl_, gl_->Uniform1i(locations.backdrop, ++last_texture_unit)); | |
1051 | |
1052 GLC(gl_, | |
1053 gl_->Uniform4f(locations.backdrop_rect, | |
1054 background_rect.x(), | |
1055 background_rect.y(), | |
1056 background_rect.width(), | |
1057 background_rect.height())); | |
1058 | |
1059 if (background_image) { | |
1060 GrTexture* texture = background_image->getTexture(); | |
1061 GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit)); | |
1062 gl_->BindTexture(GL_TEXTURE_2D, texture->getTextureHandle()); | |
1063 GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0)); | |
1064 if (mask_for_background) | |
1065 GLC(gl_, gl_->Uniform1i(locations.original_backdrop, | |
1066 ++last_texture_unit)); | |
1067 } | |
1068 if (background_texture) { | |
1069 shader_background_sampler_lock = make_scoped_ptr( | |
1070 new ResourceProvider::ScopedSamplerGL(resource_provider_, | |
1071 background_texture->id(), | |
1072 GL_TEXTURE0 + last_texture_unit, | |
1073 GL_LINEAR)); | |
1074 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), | |
1075 shader_background_sampler_lock->target()); | |
1076 } | |
1077 } | |
1078 | |
1079 SetShaderOpacity(quad->opacity(), locations.alpha); | |
1080 SetShaderQuadF(surface_quad, locations.quad); | |
1081 DrawQuadGeometry( | |
1082 frame, quad->quadTransform(), quad->rect, locations.matrix); | |
1083 | |
1084 // Flush the compositor context before the filter bitmap goes out of | |
1085 // scope, so the draw gets processed before the filter texture gets deleted. | |
1086 if (filter_image) | |
1087 GLC(gl_, gl_->Flush()); | |
1088 | |
1089 if (!use_shaders_for_blending) | |
1090 RestoreBlendFuncToDefault(blend_mode); | |
1091 } | |
1092 | |
1093 struct SolidColorProgramUniforms { | |
1094 unsigned program; | |
1095 unsigned matrix_location; | |
1096 unsigned viewport_location; | |
1097 unsigned quad_location; | |
1098 unsigned edge_location; | |
1099 unsigned color_location; | |
1100 }; | |
1101 | |
1102 template <class T> | |
1103 static void SolidColorUniformLocation(T program, | |
1104 SolidColorProgramUniforms* uniforms) { | |
1105 uniforms->program = program->program(); | |
1106 uniforms->matrix_location = program->vertex_shader().matrix_location(); | |
1107 uniforms->viewport_location = program->vertex_shader().viewport_location(); | |
1108 uniforms->quad_location = program->vertex_shader().quad_location(); | |
1109 uniforms->edge_location = program->vertex_shader().edge_location(); | |
1110 uniforms->color_location = program->fragment_shader().color_location(); | |
1111 } | |
1112 | |
1113 namespace { | |
1114 // These functions determine if a quad, clipped by a clip_region contains | |
1115 // the entire {top|bottom|left|right} edge. | |
1116 bool is_top(const gfx::QuadF* clip_region, const DrawQuad* quad) { | |
1117 if (!quad->IsTopEdge()) | |
1118 return false; | |
1119 if (!clip_region) | |
1120 return true; | |
1121 | |
1122 return std::abs(clip_region->p1().y()) < kAntiAliasingEpsilon && | |
1123 std::abs(clip_region->p2().y()) < kAntiAliasingEpsilon; | |
1124 } | |
1125 | |
1126 bool is_bottom(const gfx::QuadF* clip_region, const DrawQuad* quad) { | |
1127 if (!quad->IsBottomEdge()) | |
1128 return false; | |
1129 if (!clip_region) | |
1130 return true; | |
1131 | |
1132 return std::abs(clip_region->p3().y() - | |
1133 quad->shared_quad_state->content_bounds.height()) < | |
1134 kAntiAliasingEpsilon && | |
1135 std::abs(clip_region->p4().y() - | |
1136 quad->shared_quad_state->content_bounds.height()) < | |
1137 kAntiAliasingEpsilon; | |
1138 } | |
1139 | |
1140 bool is_left(const gfx::QuadF* clip_region, const DrawQuad* quad) { | |
1141 if (!quad->IsLeftEdge()) | |
1142 return false; | |
1143 if (!clip_region) | |
1144 return true; | |
1145 | |
1146 return std::abs(clip_region->p1().x()) < kAntiAliasingEpsilon && | |
1147 std::abs(clip_region->p4().x()) < kAntiAliasingEpsilon; | |
1148 } | |
1149 | |
1150 bool is_right(const gfx::QuadF* clip_region, const DrawQuad* quad) { | |
1151 if (!quad->IsRightEdge()) | |
1152 return false; | |
1153 if (!clip_region) | |
1154 return true; | |
1155 | |
1156 return std::abs(clip_region->p2().x() - | |
1157 quad->shared_quad_state->content_bounds.width()) < | |
1158 kAntiAliasingEpsilon && | |
1159 std::abs(clip_region->p3().x() - | |
1160 quad->shared_quad_state->content_bounds.width()) < | |
1161 kAntiAliasingEpsilon; | |
1162 } | |
1163 } // anonymous namespace | |
1164 | |
1165 static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges( | |
1166 const LayerQuad& device_layer_edges, | |
1167 const gfx::Transform& device_transform, | |
1168 const gfx::QuadF* clip_region, | |
1169 const DrawQuad* quad) { | |
1170 gfx::RectF tile_rect = quad->visible_rect; | |
1171 gfx::QuadF tile_quad(tile_rect); | |
1172 | |
1173 if (clip_region) { | |
1174 if (quad->material != DrawQuad::RENDER_PASS) { | |
1175 tile_quad = *clip_region; | |
1176 } else { | |
1177 GetScaledRegion(quad->rect, clip_region, &tile_quad); | |
1178 } | |
1179 } | |
1180 | |
1181 gfx::PointF bottom_right = tile_quad.p3(); | |
1182 gfx::PointF bottom_left = tile_quad.p4(); | |
1183 gfx::PointF top_left = tile_quad.p1(); | |
1184 gfx::PointF top_right = tile_quad.p2(); | |
1185 bool clipped = false; | |
1186 | |
1187 // Map points to device space. We ignore |clipped|, since the result of | |
1188 // |MapPoint()| still produces a valid point to draw the quad with. When | |
1189 // clipped, the point will be outside of the viewport. See crbug.com/416367. | |
1190 bottom_right = MathUtil::MapPoint(device_transform, bottom_right, &clipped); | |
1191 bottom_left = MathUtil::MapPoint(device_transform, bottom_left, &clipped); | |
1192 top_left = MathUtil::MapPoint(device_transform, top_left, &clipped); | |
1193 top_right = MathUtil::MapPoint(device_transform, top_right, &clipped); | |
1194 | |
1195 LayerQuad::Edge bottom_edge(bottom_right, bottom_left); | |
1196 LayerQuad::Edge left_edge(bottom_left, top_left); | |
1197 LayerQuad::Edge top_edge(top_left, top_right); | |
1198 LayerQuad::Edge right_edge(top_right, bottom_right); | |
1199 | |
1200 // Only apply anti-aliasing to edges not clipped by culling or scissoring. | |
1201 // If an edge is degenerate we do not want to replace it with a "proper" edge | |
1202 // as that will cause the quad to possibly expand is strange ways. | |
1203 if (!top_edge.degenerate() && is_top(clip_region, quad) && | |
1204 tile_rect.y() == quad->rect.y()) { | |
1205 top_edge = device_layer_edges.top(); | |
1206 } | |
1207 if (!left_edge.degenerate() && is_left(clip_region, quad) && | |
1208 tile_rect.x() == quad->rect.x()) { | |
1209 left_edge = device_layer_edges.left(); | |
1210 } | |
1211 if (!right_edge.degenerate() && is_right(clip_region, quad) && | |
1212 tile_rect.right() == quad->rect.right()) { | |
1213 right_edge = device_layer_edges.right(); | |
1214 } | |
1215 if (!bottom_edge.degenerate() && is_bottom(clip_region, quad) && | |
1216 tile_rect.bottom() == quad->rect.bottom()) { | |
1217 bottom_edge = device_layer_edges.bottom(); | |
1218 } | |
1219 | |
1220 float sign = tile_quad.IsCounterClockwise() ? -1 : 1; | |
1221 bottom_edge.scale(sign); | |
1222 left_edge.scale(sign); | |
1223 top_edge.scale(sign); | |
1224 right_edge.scale(sign); | |
1225 | |
1226 // Create device space quad. | |
1227 return LayerQuad(left_edge, top_edge, right_edge, bottom_edge).ToQuadF(); | |
1228 } | |
1229 | |
1230 float GetTotalQuadError(const gfx::QuadF* clipped_quad, | |
1231 const gfx::QuadF* ideal_rect) { | |
1232 return (clipped_quad->p1() - ideal_rect->p1()).LengthSquared() + | |
1233 (clipped_quad->p2() - ideal_rect->p2()).LengthSquared() + | |
1234 (clipped_quad->p3() - ideal_rect->p3()).LengthSquared() + | |
1235 (clipped_quad->p4() - ideal_rect->p4()).LengthSquared(); | |
1236 } | |
1237 | |
1238 // Attempt to rotate the clipped quad until it lines up the most | |
1239 // correctly. This is necessary because we check the edges of this | |
1240 // quad against the expected left/right/top/bottom for anti-aliasing. | |
1241 void AlignQuadToBoundingBox(gfx::QuadF* clipped_quad) { | |
1242 gfx::QuadF bounding_quad = gfx::QuadF(clipped_quad->BoundingBox()); | |
1243 gfx::QuadF best_rotation = *clipped_quad; | |
1244 float least_error_amount = GetTotalQuadError(clipped_quad, &bounding_quad); | |
1245 for (size_t i = 1; i < 4; ++i) { | |
1246 clipped_quad->Realign(1); | |
1247 float new_error = GetTotalQuadError(clipped_quad, &bounding_quad); | |
1248 if (new_error < least_error_amount) { | |
1249 least_error_amount = new_error; | |
1250 best_rotation = *clipped_quad; | |
1251 } | |
1252 } | |
1253 *clipped_quad = best_rotation; | |
1254 } | |
1255 | |
1256 // static | |
1257 bool GLRenderer::ShouldAntialiasQuad(const gfx::Transform& device_transform, | |
1258 const DrawQuad* quad, | |
1259 bool force_antialiasing) { | |
1260 bool is_render_pass_quad = (quad->material == DrawQuad::RENDER_PASS); | |
1261 // For render pass quads, |device_transform| already contains quad's rect. | |
1262 // TODO(rosca@adobe.com): remove branching on is_render_pass_quad | |
1263 // crbug.com/429702 | |
1264 if (!is_render_pass_quad && !quad->IsEdge()) | |
1265 return false; | |
1266 gfx::RectF content_rect = | |
1267 is_render_pass_quad ? QuadVertexRect() : quad->visibleContentRect(); | |
1268 | |
1269 bool clipped = false; | |
1270 gfx::QuadF device_layer_quad = | |
1271 MathUtil::MapQuad(device_transform, gfx::QuadF(content_rect), &clipped); | |
1272 | |
1273 if (device_layer_quad.BoundingBox().IsEmpty()) | |
1274 return false; | |
1275 | |
1276 bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear(); | |
1277 bool is_nearest_rect_within_epsilon = | |
1278 is_axis_aligned_in_target && | |
1279 gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(), | |
1280 kAntiAliasingEpsilon); | |
1281 // AAing clipped quads is not supported by the code yet. | |
1282 bool use_aa = !clipped && !is_nearest_rect_within_epsilon; | |
1283 return use_aa || force_antialiasing; | |
1284 } | |
1285 | |
1286 // static | |
1287 void GLRenderer::SetupQuadForClippingAndAntialiasing( | |
1288 const gfx::Transform& device_transform, | |
1289 const DrawQuad* quad, | |
1290 bool use_aa, | |
1291 const gfx::QuadF* clip_region, | |
1292 gfx::QuadF* local_quad, | |
1293 float edge[24]) { | |
1294 bool is_render_pass_quad = (quad->material == DrawQuad::RENDER_PASS); | |
1295 gfx::QuadF rotated_clip; | |
1296 const gfx::QuadF* local_clip_region = clip_region; | |
1297 if (local_clip_region) { | |
1298 rotated_clip = *clip_region; | |
1299 AlignQuadToBoundingBox(&rotated_clip); | |
1300 local_clip_region = &rotated_clip; | |
1301 } | |
1302 | |
1303 gfx::QuadF content_rect = is_render_pass_quad | |
1304 ? gfx::QuadF(QuadVertexRect()) | |
1305 : gfx::QuadF(quad->visibleContentRect()); | |
1306 if (!use_aa) { | |
1307 if (local_clip_region) { | |
1308 if (!is_render_pass_quad) { | |
1309 content_rect = *local_clip_region; | |
1310 } else { | |
1311 GetScaledRegion(quad->rect, local_clip_region, &content_rect); | |
1312 } | |
1313 *local_quad = content_rect; | |
1314 } | |
1315 return; | |
1316 } | |
1317 bool clipped = false; | |
1318 gfx::QuadF device_layer_quad = | |
1319 MathUtil::MapQuad(device_transform, content_rect, &clipped); | |
1320 | |
1321 LayerQuad device_layer_bounds(gfx::QuadF(device_layer_quad.BoundingBox())); | |
1322 device_layer_bounds.InflateAntiAliasingDistance(); | |
1323 | |
1324 LayerQuad device_layer_edges(device_layer_quad); | |
1325 device_layer_edges.InflateAntiAliasingDistance(); | |
1326 | |
1327 device_layer_edges.ToFloatArray(edge); | |
1328 device_layer_bounds.ToFloatArray(&edge[12]); | |
1329 | |
1330 // If we have a clip region then we are split, and therefore | |
1331 // by necessity, at least one of our edges is not an external | |
1332 // one. | |
1333 bool is_full_rect = quad->visible_rect == quad->rect; | |
1334 | |
1335 bool region_contains_all_outside_edges = | |
1336 is_full_rect && | |
1337 (is_top(local_clip_region, quad) && is_left(local_clip_region, quad) && | |
1338 is_bottom(local_clip_region, quad) && is_right(local_clip_region, quad)); | |
1339 | |
1340 bool use_aa_on_all_four_edges = | |
1341 !local_clip_region && | |
1342 (is_render_pass_quad || region_contains_all_outside_edges); | |
1343 | |
1344 gfx::QuadF device_quad = | |
1345 use_aa_on_all_four_edges | |
1346 ? device_layer_edges.ToQuadF() | |
1347 : GetDeviceQuadWithAntialiasingOnExteriorEdges( | |
1348 device_layer_edges, device_transform, local_clip_region, quad); | |
1349 | |
1350 // Map device space quad to local space. device_transform has no 3d | |
1351 // component since it was flattened, so we don't need to project. We should | |
1352 // have already checked that the transform was uninvertible above. | |
1353 gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization); | |
1354 bool did_invert = device_transform.GetInverse(&inverse_device_transform); | |
1355 DCHECK(did_invert); | |
1356 *local_quad = | |
1357 MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped); | |
1358 // We should not DCHECK(!clipped) here, because anti-aliasing inflation may | |
1359 // cause device_quad to become clipped. To our knowledge this scenario does | |
1360 // not need to be handled differently than the unclipped case. | |
1361 } | |
1362 | |
1363 void GLRenderer::DrawSolidColorQuad(const DrawingFrame* frame, | |
1364 const SolidColorDrawQuad* quad, | |
1365 const gfx::QuadF* clip_region) { | |
1366 gfx::Rect tile_rect = quad->visible_rect; | |
1367 | |
1368 SkColor color = quad->color; | |
1369 float opacity = quad->opacity(); | |
1370 float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity; | |
1371 | |
1372 // Early out if alpha is small enough that quad doesn't contribute to output. | |
1373 if (alpha < std::numeric_limits<float>::epsilon() && | |
1374 quad->ShouldDrawWithBlending()) | |
1375 return; | |
1376 | |
1377 gfx::Transform device_transform = | |
1378 frame->window_matrix * frame->projection_matrix * quad->quadTransform(); | |
1379 device_transform.FlattenTo2d(); | |
1380 if (!device_transform.IsInvertible()) | |
1381 return; | |
1382 | |
1383 bool force_aa = false; | |
1384 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); | |
1385 float edge[24]; | |
1386 bool use_aa = settings_->allow_antialiasing && | |
1387 !quad->force_anti_aliasing_off && | |
1388 ShouldAntialiasQuad(device_transform, quad, force_aa); | |
1389 SetupQuadForClippingAndAntialiasing(device_transform, quad, use_aa, | |
1390 clip_region, &local_quad, edge); | |
1391 | |
1392 SolidColorProgramUniforms uniforms; | |
1393 if (use_aa) { | |
1394 SolidColorUniformLocation(GetSolidColorProgramAA(), &uniforms); | |
1395 } else { | |
1396 SolidColorUniformLocation(GetSolidColorProgram(), &uniforms); | |
1397 } | |
1398 SetUseProgram(uniforms.program); | |
1399 | |
1400 GLC(gl_, | |
1401 gl_->Uniform4f(uniforms.color_location, | |
1402 (SkColorGetR(color) * (1.0f / 255.0f)) * alpha, | |
1403 (SkColorGetG(color) * (1.0f / 255.0f)) * alpha, | |
1404 (SkColorGetB(color) * (1.0f / 255.0f)) * alpha, | |
1405 alpha)); | |
1406 if (use_aa) { | |
1407 float viewport[4] = {static_cast<float>(viewport_.x()), | |
1408 static_cast<float>(viewport_.y()), | |
1409 static_cast<float>(viewport_.width()), | |
1410 static_cast<float>(viewport_.height()), }; | |
1411 GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport)); | |
1412 GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge)); | |
1413 } | |
1414 | |
1415 // Enable blending when the quad properties require it or if we decided | |
1416 // to use antialiasing. | |
1417 SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa); | |
1418 | |
1419 // Normalize to tile_rect. | |
1420 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
1421 | |
1422 SetShaderQuadF(local_quad, uniforms.quad_location); | |
1423 | |
1424 // The transform and vertex data are used to figure out the extents that the | |
1425 // un-antialiased quad should have and which vertex this is and the float | |
1426 // quad passed in via uniform is the actual geometry that gets used to draw | |
1427 // it. This is why this centered rect is used and not the original quad_rect. | |
1428 gfx::RectF centered_rect( | |
1429 gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), | |
1430 tile_rect.size()); | |
1431 DrawQuadGeometry( | |
1432 frame, quad->quadTransform(), centered_rect, uniforms.matrix_location); | |
1433 } | |
1434 | |
1435 struct TileProgramUniforms { | |
1436 unsigned program; | |
1437 unsigned matrix_location; | |
1438 unsigned viewport_location; | |
1439 unsigned quad_location; | |
1440 unsigned edge_location; | |
1441 unsigned vertex_tex_transform_location; | |
1442 unsigned sampler_location; | |
1443 unsigned fragment_tex_transform_location; | |
1444 unsigned alpha_location; | |
1445 }; | |
1446 | |
1447 template <class T> | |
1448 static void TileUniformLocation(T program, TileProgramUniforms* uniforms) { | |
1449 uniforms->program = program->program(); | |
1450 uniforms->matrix_location = program->vertex_shader().matrix_location(); | |
1451 uniforms->viewport_location = program->vertex_shader().viewport_location(); | |
1452 uniforms->quad_location = program->vertex_shader().quad_location(); | |
1453 uniforms->edge_location = program->vertex_shader().edge_location(); | |
1454 uniforms->vertex_tex_transform_location = | |
1455 program->vertex_shader().vertex_tex_transform_location(); | |
1456 | |
1457 uniforms->sampler_location = program->fragment_shader().sampler_location(); | |
1458 uniforms->alpha_location = program->fragment_shader().alpha_location(); | |
1459 uniforms->fragment_tex_transform_location = | |
1460 program->fragment_shader().fragment_tex_transform_location(); | |
1461 } | |
1462 | |
1463 void GLRenderer::DrawTileQuad(const DrawingFrame* frame, | |
1464 const TileDrawQuad* quad, | |
1465 const gfx::QuadF* clip_region) { | |
1466 DrawContentQuad(frame, quad, quad->resource_id, clip_region); | |
1467 } | |
1468 | |
1469 void GLRenderer::DrawContentQuad(const DrawingFrame* frame, | |
1470 const ContentDrawQuadBase* quad, | |
1471 ResourceProvider::ResourceId resource_id, | |
1472 const gfx::QuadF* clip_region) { | |
1473 gfx::Transform device_transform = | |
1474 frame->window_matrix * frame->projection_matrix * quad->quadTransform(); | |
1475 device_transform.FlattenTo2d(); | |
1476 | |
1477 bool use_aa = settings_->allow_antialiasing && | |
1478 ShouldAntialiasQuad(device_transform, quad, false); | |
1479 | |
1480 // TODO(timav): simplify coordinate transformations in DrawContentQuadAA | |
1481 // similar to the way DrawContentQuadNoAA works and then consider | |
1482 // combining DrawContentQuadAA and DrawContentQuadNoAA into one method. | |
1483 if (use_aa) | |
1484 DrawContentQuadAA(frame, quad, resource_id, device_transform, clip_region); | |
1485 else | |
1486 DrawContentQuadNoAA(frame, quad, resource_id, clip_region); | |
1487 } | |
1488 | |
1489 void GLRenderer::DrawContentQuadAA(const DrawingFrame* frame, | |
1490 const ContentDrawQuadBase* quad, | |
1491 ResourceProvider::ResourceId resource_id, | |
1492 const gfx::Transform& device_transform, | |
1493 const gfx::QuadF* clip_region) { | |
1494 if (!device_transform.IsInvertible()) | |
1495 return; | |
1496 | |
1497 gfx::Rect tile_rect = quad->visible_rect; | |
1498 | |
1499 gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional( | |
1500 quad->tex_coord_rect, quad->rect, tile_rect); | |
1501 float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width(); | |
1502 float tex_to_geom_scale_y = | |
1503 quad->rect.height() / quad->tex_coord_rect.height(); | |
1504 | |
1505 gfx::RectF clamp_geom_rect(tile_rect); | |
1506 gfx::RectF clamp_tex_rect(tex_coord_rect); | |
1507 // Clamp texture coordinates to avoid sampling outside the layer | |
1508 // by deflating the tile region half a texel or half a texel | |
1509 // minus epsilon for one pixel layers. The resulting clamp region | |
1510 // is mapped to the unit square by the vertex shader and mapped | |
1511 // back to normalized texture coordinates by the fragment shader | |
1512 // after being clamped to 0-1 range. | |
1513 float tex_clamp_x = | |
1514 std::min(0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon); | |
1515 float tex_clamp_y = | |
1516 std::min(0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon); | |
1517 float geom_clamp_x = | |
1518 std::min(tex_clamp_x * tex_to_geom_scale_x, | |
1519 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon); | |
1520 float geom_clamp_y = | |
1521 std::min(tex_clamp_y * tex_to_geom_scale_y, | |
1522 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon); | |
1523 clamp_geom_rect.Inset(geom_clamp_x, geom_clamp_y, geom_clamp_x, geom_clamp_y); | |
1524 clamp_tex_rect.Inset(tex_clamp_x, tex_clamp_y, tex_clamp_x, tex_clamp_y); | |
1525 | |
1526 // Map clamping rectangle to unit square. | |
1527 float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width(); | |
1528 float vertex_tex_translate_y = | |
1529 -clamp_geom_rect.y() / clamp_geom_rect.height(); | |
1530 float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width(); | |
1531 float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height(); | |
1532 | |
1533 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
1534 gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); | |
1535 | |
1536 gfx::QuadF local_quad = gfx::QuadF(gfx::RectF(tile_rect)); | |
1537 float edge[24]; | |
1538 SetupQuadForClippingAndAntialiasing(device_transform, quad, true, clip_region, | |
1539 &local_quad, edge); | |
1540 ResourceProvider::ScopedSamplerGL quad_resource_lock( | |
1541 resource_provider_, resource_id, | |
1542 quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR); | |
1543 SamplerType sampler = | |
1544 SamplerTypeFromTextureTarget(quad_resource_lock.target()); | |
1545 | |
1546 float fragment_tex_translate_x = clamp_tex_rect.x(); | |
1547 float fragment_tex_translate_y = clamp_tex_rect.y(); | |
1548 float fragment_tex_scale_x = clamp_tex_rect.width(); | |
1549 float fragment_tex_scale_y = clamp_tex_rect.height(); | |
1550 | |
1551 // Map to normalized texture coordinates. | |
1552 if (sampler != SAMPLER_TYPE_2D_RECT) { | |
1553 gfx::Size texture_size = quad->texture_size; | |
1554 DCHECK(!texture_size.IsEmpty()); | |
1555 fragment_tex_translate_x /= texture_size.width(); | |
1556 fragment_tex_translate_y /= texture_size.height(); | |
1557 fragment_tex_scale_x /= texture_size.width(); | |
1558 fragment_tex_scale_y /= texture_size.height(); | |
1559 } | |
1560 | |
1561 TileProgramUniforms uniforms; | |
1562 if (quad->swizzle_contents) { | |
1563 TileUniformLocation(GetTileProgramSwizzleAA(tex_coord_precision, sampler), | |
1564 &uniforms); | |
1565 } else { | |
1566 TileUniformLocation(GetTileProgramAA(tex_coord_precision, sampler), | |
1567 &uniforms); | |
1568 } | |
1569 | |
1570 SetUseProgram(uniforms.program); | |
1571 GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0)); | |
1572 | |
1573 float viewport[4] = { | |
1574 static_cast<float>(viewport_.x()), | |
1575 static_cast<float>(viewport_.y()), | |
1576 static_cast<float>(viewport_.width()), | |
1577 static_cast<float>(viewport_.height()), | |
1578 }; | |
1579 GLC(gl_, gl_->Uniform4fv(uniforms.viewport_location, 1, viewport)); | |
1580 GLC(gl_, gl_->Uniform3fv(uniforms.edge_location, 8, edge)); | |
1581 | |
1582 GLC(gl_, | |
1583 gl_->Uniform4f(uniforms.vertex_tex_transform_location, | |
1584 vertex_tex_translate_x, | |
1585 vertex_tex_translate_y, | |
1586 vertex_tex_scale_x, | |
1587 vertex_tex_scale_y)); | |
1588 GLC(gl_, | |
1589 gl_->Uniform4f(uniforms.fragment_tex_transform_location, | |
1590 fragment_tex_translate_x, | |
1591 fragment_tex_translate_y, | |
1592 fragment_tex_scale_x, | |
1593 fragment_tex_scale_y)); | |
1594 | |
1595 // Blending is required for antialiasing. | |
1596 SetBlendEnabled(true); | |
1597 | |
1598 // Normalize to tile_rect. | |
1599 local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
1600 | |
1601 SetShaderOpacity(quad->opacity(), uniforms.alpha_location); | |
1602 SetShaderQuadF(local_quad, uniforms.quad_location); | |
1603 | |
1604 // The transform and vertex data are used to figure out the extents that the | |
1605 // un-antialiased quad should have and which vertex this is and the float | |
1606 // quad passed in via uniform is the actual geometry that gets used to draw | |
1607 // it. This is why this centered rect is used and not the original quad_rect. | |
1608 gfx::RectF centered_rect( | |
1609 gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()), | |
1610 tile_rect.size()); | |
1611 DrawQuadGeometry( | |
1612 frame, quad->quadTransform(), centered_rect, uniforms.matrix_location); | |
1613 } | |
1614 | |
1615 void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame, | |
1616 const ContentDrawQuadBase* quad, | |
1617 ResourceProvider::ResourceId resource_id, | |
1618 const gfx::QuadF* clip_region) { | |
1619 gfx::RectF tex_coord_rect = MathUtil::ScaleRectProportional( | |
1620 quad->tex_coord_rect, quad->rect, quad->visible_rect); | |
1621 float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width(); | |
1622 float tex_to_geom_scale_y = | |
1623 quad->rect.height() / quad->tex_coord_rect.height(); | |
1624 | |
1625 bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f); | |
1626 GLenum filter = | |
1627 (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation()) && | |
1628 !quad->nearest_neighbor | |
1629 ? GL_LINEAR | |
1630 : GL_NEAREST; | |
1631 | |
1632 ResourceProvider::ScopedSamplerGL quad_resource_lock( | |
1633 resource_provider_, resource_id, filter); | |
1634 SamplerType sampler = | |
1635 SamplerTypeFromTextureTarget(quad_resource_lock.target()); | |
1636 | |
1637 float vertex_tex_translate_x = tex_coord_rect.x(); | |
1638 float vertex_tex_translate_y = tex_coord_rect.y(); | |
1639 float vertex_tex_scale_x = tex_coord_rect.width(); | |
1640 float vertex_tex_scale_y = tex_coord_rect.height(); | |
1641 | |
1642 // Map to normalized texture coordinates. | |
1643 if (sampler != SAMPLER_TYPE_2D_RECT) { | |
1644 gfx::Size texture_size = quad->texture_size; | |
1645 DCHECK(!texture_size.IsEmpty()); | |
1646 vertex_tex_translate_x /= texture_size.width(); | |
1647 vertex_tex_translate_y /= texture_size.height(); | |
1648 vertex_tex_scale_x /= texture_size.width(); | |
1649 vertex_tex_scale_y /= texture_size.height(); | |
1650 } | |
1651 | |
1652 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
1653 gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size); | |
1654 | |
1655 TileProgramUniforms uniforms; | |
1656 if (quad->ShouldDrawWithBlending()) { | |
1657 if (quad->swizzle_contents) { | |
1658 TileUniformLocation(GetTileProgramSwizzle(tex_coord_precision, sampler), | |
1659 &uniforms); | |
1660 } else { | |
1661 TileUniformLocation(GetTileProgram(tex_coord_precision, sampler), | |
1662 &uniforms); | |
1663 } | |
1664 } else { | |
1665 if (quad->swizzle_contents) { | |
1666 TileUniformLocation( | |
1667 GetTileProgramSwizzleOpaque(tex_coord_precision, sampler), &uniforms); | |
1668 } else { | |
1669 TileUniformLocation(GetTileProgramOpaque(tex_coord_precision, sampler), | |
1670 &uniforms); | |
1671 } | |
1672 } | |
1673 | |
1674 SetUseProgram(uniforms.program); | |
1675 GLC(gl_, gl_->Uniform1i(uniforms.sampler_location, 0)); | |
1676 | |
1677 GLC(gl_, | |
1678 gl_->Uniform4f(uniforms.vertex_tex_transform_location, | |
1679 vertex_tex_translate_x, | |
1680 vertex_tex_translate_y, | |
1681 vertex_tex_scale_x, | |
1682 vertex_tex_scale_y)); | |
1683 | |
1684 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
1685 | |
1686 SetShaderOpacity(quad->opacity(), uniforms.alpha_location); | |
1687 | |
1688 // Pass quad coordinates to the uniform in the same order as GeometryBinding | |
1689 // does, then vertices will match the texture mapping in the vertex buffer. | |
1690 // The method SetShaderQuadF() changes the order of vertices and so it's | |
1691 // not used here. | |
1692 gfx::QuadF tile_rect(quad->visible_rect); | |
1693 float width = quad->visible_rect.width(); | |
1694 float height = quad->visible_rect.height(); | |
1695 gfx::PointF top_left = quad->visible_rect.origin(); | |
1696 if (clip_region) { | |
1697 tile_rect = *clip_region; | |
1698 float gl_uv[8] = { | |
1699 (tile_rect.p4().x() - top_left.x()) / width, | |
1700 (tile_rect.p4().y() - top_left.y()) / height, | |
1701 (tile_rect.p1().x() - top_left.x()) / width, | |
1702 (tile_rect.p1().y() - top_left.y()) / height, | |
1703 (tile_rect.p2().x() - top_left.x()) / width, | |
1704 (tile_rect.p2().y() - top_left.y()) / height, | |
1705 (tile_rect.p3().x() - top_left.x()) / width, | |
1706 (tile_rect.p3().y() - top_left.y()) / height, | |
1707 }; | |
1708 PrepareGeometry(CLIPPED_BINDING); | |
1709 clipped_geometry_->InitializeCustomQuadWithUVs( | |
1710 gfx::QuadF(quad->visible_rect), gl_uv); | |
1711 } else { | |
1712 PrepareGeometry(SHARED_BINDING); | |
1713 } | |
1714 float gl_quad[8] = { | |
1715 tile_rect.p4().x(), | |
1716 tile_rect.p4().y(), | |
1717 tile_rect.p1().x(), | |
1718 tile_rect.p1().y(), | |
1719 tile_rect.p2().x(), | |
1720 tile_rect.p2().y(), | |
1721 tile_rect.p3().x(), | |
1722 tile_rect.p3().y(), | |
1723 }; | |
1724 GLC(gl_, gl_->Uniform2fv(uniforms.quad_location, 4, gl_quad)); | |
1725 | |
1726 static float gl_matrix[16]; | |
1727 ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad->quadTransform()); | |
1728 GLC(gl_, | |
1729 gl_->UniformMatrix4fv(uniforms.matrix_location, 1, false, &gl_matrix[0])); | |
1730 | |
1731 GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); | |
1732 } | |
1733 | |
1734 void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame, | |
1735 const YUVVideoDrawQuad* quad, | |
1736 const gfx::QuadF* clip_region) { | |
1737 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
1738 | |
1739 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
1740 gl_, | |
1741 &highp_threshold_cache_, | |
1742 highp_threshold_min_, | |
1743 quad->shared_quad_state->visible_content_rect.bottom_right()); | |
1744 | |
1745 bool use_alpha_plane = quad->a_plane_resource_id != 0; | |
1746 | |
1747 ResourceProvider::ScopedSamplerGL y_plane_lock( | |
1748 resource_provider_, quad->y_plane_resource_id, GL_TEXTURE1, GL_LINEAR); | |
1749 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), y_plane_lock.target()); | |
1750 ResourceProvider::ScopedSamplerGL u_plane_lock( | |
1751 resource_provider_, quad->u_plane_resource_id, GL_TEXTURE2, GL_LINEAR); | |
1752 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), u_plane_lock.target()); | |
1753 ResourceProvider::ScopedSamplerGL v_plane_lock( | |
1754 resource_provider_, quad->v_plane_resource_id, GL_TEXTURE3, GL_LINEAR); | |
1755 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), v_plane_lock.target()); | |
1756 scoped_ptr<ResourceProvider::ScopedSamplerGL> a_plane_lock; | |
1757 if (use_alpha_plane) { | |
1758 a_plane_lock.reset(new ResourceProvider::ScopedSamplerGL( | |
1759 resource_provider_, quad->a_plane_resource_id, GL_TEXTURE4, GL_LINEAR)); | |
1760 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), a_plane_lock->target()); | |
1761 } | |
1762 | |
1763 int matrix_location = -1; | |
1764 int tex_scale_location = -1; | |
1765 int tex_offset_location = -1; | |
1766 int clamp_rect_location = -1; | |
1767 int y_texture_location = -1; | |
1768 int u_texture_location = -1; | |
1769 int v_texture_location = -1; | |
1770 int a_texture_location = -1; | |
1771 int yuv_matrix_location = -1; | |
1772 int yuv_adj_location = -1; | |
1773 int alpha_location = -1; | |
1774 if (use_alpha_plane) { | |
1775 const VideoYUVAProgram* program = GetVideoYUVAProgram(tex_coord_precision); | |
1776 DCHECK(program && (program->initialized() || IsContextLost())); | |
1777 SetUseProgram(program->program()); | |
1778 matrix_location = program->vertex_shader().matrix_location(); | |
1779 tex_scale_location = program->vertex_shader().tex_scale_location(); | |
1780 tex_offset_location = program->vertex_shader().tex_offset_location(); | |
1781 y_texture_location = program->fragment_shader().y_texture_location(); | |
1782 u_texture_location = program->fragment_shader().u_texture_location(); | |
1783 v_texture_location = program->fragment_shader().v_texture_location(); | |
1784 a_texture_location = program->fragment_shader().a_texture_location(); | |
1785 yuv_matrix_location = program->fragment_shader().yuv_matrix_location(); | |
1786 yuv_adj_location = program->fragment_shader().yuv_adj_location(); | |
1787 clamp_rect_location = program->fragment_shader().clamp_rect_location(); | |
1788 alpha_location = program->fragment_shader().alpha_location(); | |
1789 } else { | |
1790 const VideoYUVProgram* program = GetVideoYUVProgram(tex_coord_precision); | |
1791 DCHECK(program && (program->initialized() || IsContextLost())); | |
1792 SetUseProgram(program->program()); | |
1793 matrix_location = program->vertex_shader().matrix_location(); | |
1794 tex_scale_location = program->vertex_shader().tex_scale_location(); | |
1795 tex_offset_location = program->vertex_shader().tex_offset_location(); | |
1796 y_texture_location = program->fragment_shader().y_texture_location(); | |
1797 u_texture_location = program->fragment_shader().u_texture_location(); | |
1798 v_texture_location = program->fragment_shader().v_texture_location(); | |
1799 yuv_matrix_location = program->fragment_shader().yuv_matrix_location(); | |
1800 yuv_adj_location = program->fragment_shader().yuv_adj_location(); | |
1801 clamp_rect_location = program->fragment_shader().clamp_rect_location(); | |
1802 alpha_location = program->fragment_shader().alpha_location(); | |
1803 } | |
1804 | |
1805 GLC(gl_, | |
1806 gl_->Uniform2f(tex_scale_location, | |
1807 quad->tex_coord_rect.width(), | |
1808 quad->tex_coord_rect.height())); | |
1809 GLC(gl_, | |
1810 gl_->Uniform2f(tex_offset_location, | |
1811 quad->tex_coord_rect.x(), | |
1812 quad->tex_coord_rect.y())); | |
1813 // Clamping to half a texel inside the tex coord rect prevents bilinear | |
1814 // filtering from filtering outside the tex coord rect. | |
1815 gfx::RectF clamp_rect(quad->tex_coord_rect); | |
1816 // Special case: empty texture size implies no clamping. | |
1817 if (!quad->tex_size.IsEmpty()) { | |
1818 clamp_rect.Inset(0.5f / quad->tex_size.width(), | |
1819 0.5f / quad->tex_size.height()); | |
1820 } | |
1821 GLC(gl_, gl_->Uniform4f(clamp_rect_location, clamp_rect.x(), clamp_rect.y(), | |
1822 clamp_rect.right(), clamp_rect.bottom())); | |
1823 | |
1824 GLC(gl_, gl_->Uniform1i(y_texture_location, 1)); | |
1825 GLC(gl_, gl_->Uniform1i(u_texture_location, 2)); | |
1826 GLC(gl_, gl_->Uniform1i(v_texture_location, 3)); | |
1827 if (use_alpha_plane) | |
1828 GLC(gl_, gl_->Uniform1i(a_texture_location, 4)); | |
1829 | |
1830 // These values are magic numbers that are used in the transformation from YUV | |
1831 // to RGB color values. They are taken from the following webpage: | |
1832 // http://www.fourcc.org/fccyvrgb.php | |
1833 float yuv_to_rgb_rec601[9] = { | |
1834 1.164f, 1.164f, 1.164f, 0.0f, -.391f, 2.018f, 1.596f, -.813f, 0.0f, | |
1835 }; | |
1836 float yuv_to_rgb_jpeg[9] = { | |
1837 1.f, 1.f, 1.f, 0.0f, -.34414f, 1.772f, 1.402f, -.71414f, 0.0f, | |
1838 }; | |
1839 float yuv_to_rgb_rec709[9] = { | |
1840 1.164f, 1.164f, 1.164f, 0.0f, -0.213f, 2.112f, 1.793f, -0.533f, 0.0f, | |
1841 }; | |
1842 | |
1843 // These values map to 16, 128, and 128 respectively, and are computed | |
1844 // as a fraction over 256 (e.g. 16 / 256 = 0.0625). | |
1845 // They are used in the YUV to RGBA conversion formula: | |
1846 // Y - 16 : Gives 16 values of head and footroom for overshooting | |
1847 // U - 128 : Turns unsigned U into signed U [-128,127] | |
1848 // V - 128 : Turns unsigned V into signed V [-128,127] | |
1849 float yuv_adjust_constrained[3] = { | |
1850 -0.0625f, -0.5f, -0.5f, | |
1851 }; | |
1852 | |
1853 // Same as above, but without the head and footroom. | |
1854 float yuv_adjust_full[3] = { | |
1855 0.0f, -0.5f, -0.5f, | |
1856 }; | |
1857 | |
1858 float* yuv_to_rgb = NULL; | |
1859 float* yuv_adjust = NULL; | |
1860 | |
1861 switch (quad->color_space) { | |
1862 case YUVVideoDrawQuad::REC_601: | |
1863 yuv_to_rgb = yuv_to_rgb_rec601; | |
1864 yuv_adjust = yuv_adjust_constrained; | |
1865 break; | |
1866 case YUVVideoDrawQuad::REC_709: | |
1867 yuv_to_rgb = yuv_to_rgb_rec709; | |
1868 yuv_adjust = yuv_adjust_constrained; | |
1869 break; | |
1870 case YUVVideoDrawQuad::JPEG: | |
1871 yuv_to_rgb = yuv_to_rgb_jpeg; | |
1872 yuv_adjust = yuv_adjust_full; | |
1873 break; | |
1874 } | |
1875 | |
1876 // The transform and vertex data are used to figure out the extents that the | |
1877 // un-antialiased quad should have and which vertex this is and the float | |
1878 // quad passed in via uniform is the actual geometry that gets used to draw | |
1879 // it. This is why this centered rect is used and not the original quad_rect. | |
1880 gfx::RectF tile_rect = quad->rect; | |
1881 GLC(gl_, gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb)); | |
1882 GLC(gl_, gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust)); | |
1883 | |
1884 SetShaderOpacity(quad->opacity(), alpha_location); | |
1885 if (!clip_region) { | |
1886 DrawQuadGeometry(frame, quad->quadTransform(), tile_rect, matrix_location); | |
1887 } else { | |
1888 float uvs[8] = {0}; | |
1889 GetScaledUVs(quad->visible_rect, clip_region, uvs); | |
1890 gfx::QuadF region_quad = *clip_region; | |
1891 region_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height()); | |
1892 region_quad -= gfx::Vector2dF(0.5f, 0.5f); | |
1893 DrawQuadGeometryClippedByQuadF(frame, quad->quadTransform(), tile_rect, | |
1894 region_quad, matrix_location, uvs); | |
1895 } | |
1896 } | |
1897 | |
1898 void GLRenderer::DrawStreamVideoQuad(const DrawingFrame* frame, | |
1899 const StreamVideoDrawQuad* quad, | |
1900 const gfx::QuadF* clip_region) { | |
1901 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
1902 | |
1903 static float gl_matrix[16]; | |
1904 | |
1905 DCHECK(capabilities_.using_egl_image); | |
1906 | |
1907 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
1908 gl_, | |
1909 &highp_threshold_cache_, | |
1910 highp_threshold_min_, | |
1911 quad->shared_quad_state->visible_content_rect.bottom_right()); | |
1912 | |
1913 const VideoStreamTextureProgram* program = | |
1914 GetVideoStreamTextureProgram(tex_coord_precision); | |
1915 SetUseProgram(program->program()); | |
1916 | |
1917 ToGLMatrix(&gl_matrix[0], quad->matrix); | |
1918 GLC(gl_, | |
1919 gl_->UniformMatrix4fv( | |
1920 program->vertex_shader().tex_matrix_location(), 1, false, gl_matrix)); | |
1921 | |
1922 ResourceProvider::ScopedReadLockGL lock(resource_provider_, | |
1923 quad->resource_id); | |
1924 DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); | |
1925 GLC(gl_, gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id())); | |
1926 | |
1927 GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0)); | |
1928 | |
1929 SetShaderOpacity(quad->opacity(), | |
1930 program->fragment_shader().alpha_location()); | |
1931 if (!clip_region) { | |
1932 DrawQuadGeometry(frame, quad->quadTransform(), quad->rect, | |
1933 program->vertex_shader().matrix_location()); | |
1934 } else { | |
1935 gfx::QuadF region_quad(*clip_region); | |
1936 region_quad.Scale(1.0f / quad->rect.width(), 1.0f / quad->rect.height()); | |
1937 region_quad -= gfx::Vector2dF(0.5f, 0.5f); | |
1938 float uvs[8] = {0}; | |
1939 GetScaledUVs(quad->visible_rect, clip_region, uvs); | |
1940 DrawQuadGeometryClippedByQuadF( | |
1941 frame, quad->quadTransform(), quad->rect, region_quad, | |
1942 program->vertex_shader().matrix_location(), uvs); | |
1943 } | |
1944 } | |
1945 | |
1946 struct TextureProgramBinding { | |
1947 template <class Program> | |
1948 void Set(Program* program) { | |
1949 DCHECK(program); | |
1950 program_id = program->program(); | |
1951 sampler_location = program->fragment_shader().sampler_location(); | |
1952 matrix_location = program->vertex_shader().matrix_location(); | |
1953 background_color_location = | |
1954 program->fragment_shader().background_color_location(); | |
1955 } | |
1956 int program_id; | |
1957 int sampler_location; | |
1958 int matrix_location; | |
1959 int transform_location; | |
1960 int background_color_location; | |
1961 }; | |
1962 | |
1963 struct TexTransformTextureProgramBinding : TextureProgramBinding { | |
1964 template <class Program> | |
1965 void Set(Program* program) { | |
1966 TextureProgramBinding::Set(program); | |
1967 tex_transform_location = program->vertex_shader().tex_transform_location(); | |
1968 vertex_opacity_location = | |
1969 program->vertex_shader().vertex_opacity_location(); | |
1970 } | |
1971 int tex_transform_location; | |
1972 int vertex_opacity_location; | |
1973 }; | |
1974 | |
1975 void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) { | |
1976 // Check to see if we have anything to draw. | |
1977 if (draw_cache_.program_id == -1) | |
1978 return; | |
1979 | |
1980 PrepareGeometry(flush_binding); | |
1981 | |
1982 // Set the correct blending mode. | |
1983 SetBlendEnabled(draw_cache_.needs_blending); | |
1984 | |
1985 // Bind the program to the GL state. | |
1986 SetUseProgram(draw_cache_.program_id); | |
1987 | |
1988 // Bind the correct texture sampler location. | |
1989 GLC(gl_, gl_->Uniform1i(draw_cache_.sampler_location, 0)); | |
1990 | |
1991 // Assume the current active textures is 0. | |
1992 ResourceProvider::ScopedSamplerGL locked_quad( | |
1993 resource_provider_, | |
1994 draw_cache_.resource_id, | |
1995 draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR); | |
1996 DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); | |
1997 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, locked_quad.texture_id())); | |
1998 | |
1999 static_assert(sizeof(Float4) == 4 * sizeof(float), | |
2000 "Float4 struct should be densely packed"); | |
2001 static_assert(sizeof(Float16) == 16 * sizeof(float), | |
2002 "Float16 struct should be densely packed"); | |
2003 | |
2004 // Upload the tranforms for both points and uvs. | |
2005 GLC(gl_, | |
2006 gl_->UniformMatrix4fv( | |
2007 static_cast<int>(draw_cache_.matrix_location), | |
2008 static_cast<int>(draw_cache_.matrix_data.size()), | |
2009 false, | |
2010 reinterpret_cast<float*>(&draw_cache_.matrix_data.front()))); | |
2011 GLC(gl_, | |
2012 gl_->Uniform4fv( | |
2013 static_cast<int>(draw_cache_.uv_xform_location), | |
2014 static_cast<int>(draw_cache_.uv_xform_data.size()), | |
2015 reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()))); | |
2016 | |
2017 if (draw_cache_.background_color != SK_ColorTRANSPARENT) { | |
2018 Float4 background_color = PremultipliedColor(draw_cache_.background_color); | |
2019 GLC(gl_, | |
2020 gl_->Uniform4fv( | |
2021 draw_cache_.background_color_location, 1, background_color.data)); | |
2022 } | |
2023 | |
2024 GLC(gl_, | |
2025 gl_->Uniform1fv( | |
2026 static_cast<int>(draw_cache_.vertex_opacity_location), | |
2027 static_cast<int>(draw_cache_.vertex_opacity_data.size()), | |
2028 static_cast<float*>(&draw_cache_.vertex_opacity_data.front()))); | |
2029 | |
2030 // Draw the quads! | |
2031 GLC(gl_, | |
2032 gl_->DrawElements(GL_TRIANGLES, | |
2033 6 * draw_cache_.matrix_data.size(), | |
2034 GL_UNSIGNED_SHORT, | |
2035 0)); | |
2036 | |
2037 // Clear the cache. | |
2038 draw_cache_.program_id = -1; | |
2039 draw_cache_.uv_xform_data.resize(0); | |
2040 draw_cache_.vertex_opacity_data.resize(0); | |
2041 draw_cache_.matrix_data.resize(0); | |
2042 | |
2043 // If we had a clipped binding, prepare the shared binding for the | |
2044 // next inserts. | |
2045 if (flush_binding == CLIPPED_BINDING) { | |
2046 PrepareGeometry(SHARED_BINDING); | |
2047 } | |
2048 } | |
2049 | |
2050 void GLRenderer::EnqueueTextureQuad(const DrawingFrame* frame, | |
2051 const TextureDrawQuad* quad, | |
2052 const gfx::QuadF* clip_region) { | |
2053 // If we have a clip_region then we have to render the next quad | |
2054 // with dynamic geometry, therefore we must flush all pending | |
2055 // texture quads. | |
2056 if (clip_region) { | |
2057 // We send in false here because we want to flush what's currently in the | |
2058 // queue using the shared_geometry and not clipped_geometry | |
2059 FlushTextureQuadCache(SHARED_BINDING); | |
2060 } | |
2061 | |
2062 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
2063 gl_, | |
2064 &highp_threshold_cache_, | |
2065 highp_threshold_min_, | |
2066 quad->shared_quad_state->visible_content_rect.bottom_right()); | |
2067 | |
2068 // Choose the correct texture program binding | |
2069 TexTransformTextureProgramBinding binding; | |
2070 if (quad->premultiplied_alpha) { | |
2071 if (quad->background_color == SK_ColorTRANSPARENT) { | |
2072 binding.Set(GetTextureProgram(tex_coord_precision)); | |
2073 } else { | |
2074 binding.Set(GetTextureBackgroundProgram(tex_coord_precision)); | |
2075 } | |
2076 } else { | |
2077 if (quad->background_color == SK_ColorTRANSPARENT) { | |
2078 binding.Set(GetNonPremultipliedTextureProgram(tex_coord_precision)); | |
2079 } else { | |
2080 binding.Set( | |
2081 GetNonPremultipliedTextureBackgroundProgram(tex_coord_precision)); | |
2082 } | |
2083 } | |
2084 | |
2085 int resource_id = quad->resource_id; | |
2086 | |
2087 if (draw_cache_.program_id != binding.program_id || | |
2088 draw_cache_.resource_id != resource_id || | |
2089 draw_cache_.needs_blending != quad->ShouldDrawWithBlending() || | |
2090 draw_cache_.nearest_neighbor != quad->nearest_neighbor || | |
2091 draw_cache_.background_color != quad->background_color || | |
2092 draw_cache_.matrix_data.size() >= 8) { | |
2093 FlushTextureQuadCache(SHARED_BINDING); | |
2094 draw_cache_.program_id = binding.program_id; | |
2095 draw_cache_.resource_id = resource_id; | |
2096 draw_cache_.needs_blending = quad->ShouldDrawWithBlending(); | |
2097 draw_cache_.nearest_neighbor = quad->nearest_neighbor; | |
2098 draw_cache_.background_color = quad->background_color; | |
2099 | |
2100 draw_cache_.uv_xform_location = binding.tex_transform_location; | |
2101 draw_cache_.background_color_location = binding.background_color_location; | |
2102 draw_cache_.vertex_opacity_location = binding.vertex_opacity_location; | |
2103 draw_cache_.matrix_location = binding.matrix_location; | |
2104 draw_cache_.sampler_location = binding.sampler_location; | |
2105 } | |
2106 | |
2107 // Generate the uv-transform | |
2108 if (!clip_region) { | |
2109 draw_cache_.uv_xform_data.push_back(UVTransform(quad)); | |
2110 } else { | |
2111 Float4 uv_transform = {{0.0f, 0.0f, 1.0f, 1.0f}}; | |
2112 draw_cache_.uv_xform_data.push_back(uv_transform); | |
2113 } | |
2114 | |
2115 // Generate the vertex opacity | |
2116 const float opacity = quad->opacity(); | |
2117 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity); | |
2118 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity); | |
2119 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity); | |
2120 draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity); | |
2121 | |
2122 // Generate the transform matrix | |
2123 gfx::Transform quad_rect_matrix; | |
2124 QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect); | |
2125 quad_rect_matrix = frame->projection_matrix * quad_rect_matrix; | |
2126 | |
2127 Float16 m; | |
2128 quad_rect_matrix.matrix().asColMajorf(m.data); | |
2129 draw_cache_.matrix_data.push_back(m); | |
2130 | |
2131 if (clip_region) { | |
2132 gfx::QuadF scaled_region; | |
2133 if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) { | |
2134 scaled_region = SharedGeometryQuad().BoundingBox(); | |
2135 } | |
2136 // Both the scaled region and the SharedGeomtryQuad are in the space | |
2137 // -0.5->0.5. We need to move that to the space 0->1. | |
2138 float uv[8]; | |
2139 uv[0] = scaled_region.p1().x() + 0.5f; | |
2140 uv[1] = scaled_region.p1().y() + 0.5f; | |
2141 uv[2] = scaled_region.p2().x() + 0.5f; | |
2142 uv[3] = scaled_region.p2().y() + 0.5f; | |
2143 uv[4] = scaled_region.p3().x() + 0.5f; | |
2144 uv[5] = scaled_region.p3().y() + 0.5f; | |
2145 uv[6] = scaled_region.p4().x() + 0.5f; | |
2146 uv[7] = scaled_region.p4().y() + 0.5f; | |
2147 PrepareGeometry(CLIPPED_BINDING); | |
2148 clipped_geometry_->InitializeCustomQuadWithUVs(scaled_region, uv); | |
2149 FlushTextureQuadCache(CLIPPED_BINDING); | |
2150 } | |
2151 } | |
2152 | |
2153 void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame, | |
2154 const IOSurfaceDrawQuad* quad, | |
2155 const gfx::QuadF* clip_region) { | |
2156 SetBlendEnabled(quad->ShouldDrawWithBlending()); | |
2157 | |
2158 TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired( | |
2159 gl_, | |
2160 &highp_threshold_cache_, | |
2161 highp_threshold_min_, | |
2162 quad->shared_quad_state->visible_content_rect.bottom_right()); | |
2163 | |
2164 TexTransformTextureProgramBinding binding; | |
2165 binding.Set(GetTextureIOSurfaceProgram(tex_coord_precision)); | |
2166 | |
2167 SetUseProgram(binding.program_id); | |
2168 GLC(gl_, gl_->Uniform1i(binding.sampler_location, 0)); | |
2169 if (quad->orientation == IOSurfaceDrawQuad::FLIPPED) { | |
2170 GLC(gl_, | |
2171 gl_->Uniform4f(binding.tex_transform_location, | |
2172 0, | |
2173 quad->io_surface_size.height(), | |
2174 quad->io_surface_size.width(), | |
2175 quad->io_surface_size.height() * -1.0f)); | |
2176 } else { | |
2177 GLC(gl_, | |
2178 gl_->Uniform4f(binding.tex_transform_location, | |
2179 0, | |
2180 0, | |
2181 quad->io_surface_size.width(), | |
2182 quad->io_surface_size.height())); | |
2183 } | |
2184 | |
2185 const float vertex_opacity[] = {quad->opacity(), quad->opacity(), | |
2186 quad->opacity(), quad->opacity()}; | |
2187 GLC(gl_, gl_->Uniform1fv(binding.vertex_opacity_location, 4, vertex_opacity)); | |
2188 | |
2189 ResourceProvider::ScopedReadLockGL lock(resource_provider_, | |
2190 quad->io_surface_resource_id); | |
2191 DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); | |
2192 GLC(gl_, gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, lock.texture_id())); | |
2193 | |
2194 if (!clip_region) { | |
2195 DrawQuadGeometry(frame, quad->quadTransform(), quad->rect, | |
2196 binding.matrix_location); | |
2197 } else { | |
2198 float uvs[8] = {0}; | |
2199 GetScaledUVs(quad->visible_rect, clip_region, uvs); | |
2200 DrawQuadGeometryClippedByQuadF(frame, quad->quadTransform(), quad->rect, | |
2201 *clip_region, binding.matrix_location, uvs); | |
2202 } | |
2203 | |
2204 GLC(gl_, gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, 0)); | |
2205 } | |
2206 | |
2207 void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) { | |
2208 if (use_sync_query_) { | |
2209 DCHECK(current_sync_query_); | |
2210 current_sync_query_->End(); | |
2211 pending_sync_queries_.push_back(current_sync_query_.Pass()); | |
2212 } | |
2213 | |
2214 current_framebuffer_lock_ = nullptr; | |
2215 swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect)); | |
2216 | |
2217 GLC(gl_, gl_->Disable(GL_BLEND)); | |
2218 blend_shadow_ = false; | |
2219 | |
2220 ScheduleOverlays(frame); | |
2221 } | |
2222 | |
2223 void GLRenderer::FinishDrawingQuadList() { | |
2224 FlushTextureQuadCache(SHARED_BINDING); | |
2225 } | |
2226 | |
2227 bool GLRenderer::FlippedFramebuffer(const DrawingFrame* frame) const { | |
2228 if (frame->current_render_pass != frame->root_render_pass) | |
2229 return true; | |
2230 return FlippedRootFramebuffer(); | |
2231 } | |
2232 | |
2233 bool GLRenderer::FlippedRootFramebuffer() const { | |
2234 // GL is normally flipped, so a flipped output results in an unflipping. | |
2235 return !output_surface_->capabilities().flipped_output_surface; | |
2236 } | |
2237 | |
2238 void GLRenderer::EnsureScissorTestEnabled() { | |
2239 if (is_scissor_enabled_) | |
2240 return; | |
2241 | |
2242 FlushTextureQuadCache(SHARED_BINDING); | |
2243 GLC(gl_, gl_->Enable(GL_SCISSOR_TEST)); | |
2244 is_scissor_enabled_ = true; | |
2245 } | |
2246 | |
2247 void GLRenderer::EnsureScissorTestDisabled() { | |
2248 if (!is_scissor_enabled_) | |
2249 return; | |
2250 | |
2251 FlushTextureQuadCache(SHARED_BINDING); | |
2252 GLC(gl_, gl_->Disable(GL_SCISSOR_TEST)); | |
2253 is_scissor_enabled_ = false; | |
2254 } | |
2255 | |
2256 void GLRenderer::CopyCurrentRenderPassToBitmap( | |
2257 DrawingFrame* frame, | |
2258 scoped_ptr<CopyOutputRequest> request) { | |
2259 TRACE_EVENT0("cc", "GLRenderer::CopyCurrentRenderPassToBitmap"); | |
2260 gfx::Rect copy_rect = frame->current_render_pass->output_rect; | |
2261 if (request->has_area()) | |
2262 copy_rect.Intersect(request->area()); | |
2263 GetFramebufferPixelsAsync(frame, copy_rect, request.Pass()); | |
2264 } | |
2265 | |
2266 void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) { | |
2267 transform.matrix().asColMajorf(gl_matrix); | |
2268 } | |
2269 | |
2270 void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad, int quad_location) { | |
2271 if (quad_location == -1) | |
2272 return; | |
2273 | |
2274 float gl_quad[8]; | |
2275 gl_quad[0] = quad.p1().x(); | |
2276 gl_quad[1] = quad.p1().y(); | |
2277 gl_quad[2] = quad.p2().x(); | |
2278 gl_quad[3] = quad.p2().y(); | |
2279 gl_quad[4] = quad.p3().x(); | |
2280 gl_quad[5] = quad.p3().y(); | |
2281 gl_quad[6] = quad.p4().x(); | |
2282 gl_quad[7] = quad.p4().y(); | |
2283 GLC(gl_, gl_->Uniform2fv(quad_location, 4, gl_quad)); | |
2284 } | |
2285 | |
2286 void GLRenderer::SetShaderOpacity(float opacity, int alpha_location) { | |
2287 if (alpha_location != -1) | |
2288 GLC(gl_, gl_->Uniform1f(alpha_location, opacity)); | |
2289 } | |
2290 | |
2291 void GLRenderer::SetStencilEnabled(bool enabled) { | |
2292 if (enabled == stencil_shadow_) | |
2293 return; | |
2294 | |
2295 if (enabled) | |
2296 GLC(gl_, gl_->Enable(GL_STENCIL_TEST)); | |
2297 else | |
2298 GLC(gl_, gl_->Disable(GL_STENCIL_TEST)); | |
2299 stencil_shadow_ = enabled; | |
2300 } | |
2301 | |
2302 void GLRenderer::SetBlendEnabled(bool enabled) { | |
2303 if (enabled == blend_shadow_) | |
2304 return; | |
2305 | |
2306 if (enabled) | |
2307 GLC(gl_, gl_->Enable(GL_BLEND)); | |
2308 else | |
2309 GLC(gl_, gl_->Disable(GL_BLEND)); | |
2310 blend_shadow_ = enabled; | |
2311 } | |
2312 | |
2313 void GLRenderer::SetUseProgram(unsigned program) { | |
2314 if (program == program_shadow_) | |
2315 return; | |
2316 gl_->UseProgram(program); | |
2317 program_shadow_ = program; | |
2318 } | |
2319 | |
2320 void GLRenderer::DrawQuadGeometryClippedByQuadF( | |
2321 const DrawingFrame* frame, | |
2322 const gfx::Transform& draw_transform, | |
2323 const gfx::RectF& quad_rect, | |
2324 const gfx::QuadF& clipping_region_quad, | |
2325 int matrix_location, | |
2326 const float* uvs) { | |
2327 PrepareGeometry(CLIPPED_BINDING); | |
2328 if (uvs) { | |
2329 clipped_geometry_->InitializeCustomQuadWithUVs(clipping_region_quad, uvs); | |
2330 } else { | |
2331 clipped_geometry_->InitializeCustomQuad(clipping_region_quad); | |
2332 } | |
2333 gfx::Transform quad_rect_matrix; | |
2334 QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect); | |
2335 static float gl_matrix[16]; | |
2336 ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix); | |
2337 GLC(gl_, gl_->UniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0])); | |
2338 | |
2339 GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, | |
2340 reinterpret_cast<const void*>(0))); | |
2341 } | |
2342 | |
2343 void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame, | |
2344 const gfx::Transform& draw_transform, | |
2345 const gfx::RectF& quad_rect, | |
2346 int matrix_location) { | |
2347 PrepareGeometry(SHARED_BINDING); | |
2348 gfx::Transform quad_rect_matrix; | |
2349 QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect); | |
2350 static float gl_matrix[16]; | |
2351 ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad_rect_matrix); | |
2352 GLC(gl_, gl_->UniformMatrix4fv(matrix_location, 1, false, &gl_matrix[0])); | |
2353 | |
2354 GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)); | |
2355 } | |
2356 | |
2357 void GLRenderer::Finish() { | |
2358 TRACE_EVENT0("cc", "GLRenderer::Finish"); | |
2359 GLC(gl_, gl_->Finish()); | |
2360 } | |
2361 | |
2362 void GLRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) { | |
2363 DCHECK(!is_backbuffer_discarded_); | |
2364 | |
2365 TRACE_EVENT0("cc,benchmark", "GLRenderer::SwapBuffers"); | |
2366 // We're done! Time to swapbuffers! | |
2367 | |
2368 gfx::Size surface_size = output_surface_->SurfaceSize(); | |
2369 | |
2370 CompositorFrame compositor_frame; | |
2371 compositor_frame.metadata = metadata; | |
2372 compositor_frame.gl_frame_data = make_scoped_ptr(new GLFrameData); | |
2373 compositor_frame.gl_frame_data->size = surface_size; | |
2374 if (capabilities_.using_partial_swap) { | |
2375 // If supported, we can save significant bandwidth by only swapping the | |
2376 // damaged/scissored region (clamped to the viewport). | |
2377 swap_buffer_rect_.Intersect(gfx::Rect(surface_size)); | |
2378 int flipped_y_pos_of_rect_bottom = surface_size.height() - | |
2379 swap_buffer_rect_.y() - | |
2380 swap_buffer_rect_.height(); | |
2381 compositor_frame.gl_frame_data->sub_buffer_rect = | |
2382 gfx::Rect(swap_buffer_rect_.x(), | |
2383 FlippedRootFramebuffer() ? flipped_y_pos_of_rect_bottom | |
2384 : swap_buffer_rect_.y(), | |
2385 swap_buffer_rect_.width(), | |
2386 swap_buffer_rect_.height()); | |
2387 } else { | |
2388 compositor_frame.gl_frame_data->sub_buffer_rect = | |
2389 gfx::Rect(output_surface_->SurfaceSize()); | |
2390 } | |
2391 output_surface_->SwapBuffers(&compositor_frame); | |
2392 | |
2393 // Release previously used overlay resources and hold onto the pending ones | |
2394 // until the next swap buffers. | |
2395 in_use_overlay_resources_.clear(); | |
2396 in_use_overlay_resources_.swap(pending_overlay_resources_); | |
2397 | |
2398 swap_buffer_rect_ = gfx::Rect(); | |
2399 } | |
2400 | |
2401 void GLRenderer::EnforceMemoryPolicy() { | |
2402 if (!visible()) { | |
2403 TRACE_EVENT0("cc", "GLRenderer::EnforceMemoryPolicy dropping resources"); | |
2404 ReleaseRenderPassTextures(); | |
2405 DiscardBackbuffer(); | |
2406 resource_provider_->ReleaseCachedData(); | |
2407 output_surface_->context_provider()->DeleteCachedResources(); | |
2408 GLC(gl_, gl_->Flush()); | |
2409 } | |
2410 PrepareGeometry(NO_BINDING); | |
2411 } | |
2412 | |
2413 void GLRenderer::DiscardBackbuffer() { | |
2414 if (is_backbuffer_discarded_) | |
2415 return; | |
2416 | |
2417 output_surface_->DiscardBackbuffer(); | |
2418 | |
2419 is_backbuffer_discarded_ = true; | |
2420 | |
2421 // Damage tracker needs a full reset every time framebuffer is discarded. | |
2422 client_->SetFullRootLayerDamage(); | |
2423 } | |
2424 | |
2425 void GLRenderer::EnsureBackbuffer() { | |
2426 if (!is_backbuffer_discarded_) | |
2427 return; | |
2428 | |
2429 output_surface_->EnsureBackbuffer(); | |
2430 is_backbuffer_discarded_ = false; | |
2431 } | |
2432 | |
2433 void GLRenderer::GetFramebufferPixelsAsync( | |
2434 const DrawingFrame* frame, | |
2435 const gfx::Rect& rect, | |
2436 scoped_ptr<CopyOutputRequest> request) { | |
2437 DCHECK(!request->IsEmpty()); | |
2438 if (request->IsEmpty()) | |
2439 return; | |
2440 if (rect.IsEmpty()) | |
2441 return; | |
2442 | |
2443 gfx::Rect window_rect = MoveFromDrawToWindowSpace(frame, rect); | |
2444 DCHECK_GE(window_rect.x(), 0); | |
2445 DCHECK_GE(window_rect.y(), 0); | |
2446 DCHECK_LE(window_rect.right(), current_surface_size_.width()); | |
2447 DCHECK_LE(window_rect.bottom(), current_surface_size_.height()); | |
2448 | |
2449 if (!request->force_bitmap_result()) { | |
2450 bool own_mailbox = !request->has_texture_mailbox(); | |
2451 | |
2452 GLuint texture_id = 0; | |
2453 gpu::Mailbox mailbox; | |
2454 if (own_mailbox) { | |
2455 GLC(gl_, gl_->GenMailboxCHROMIUM(mailbox.name)); | |
2456 gl_->GenTextures(1, &texture_id); | |
2457 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id)); | |
2458 | |
2459 GLC(gl_, | |
2460 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | |
2461 GLC(gl_, | |
2462 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | |
2463 GLC(gl_, | |
2464 gl_->TexParameteri( | |
2465 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); | |
2466 GLC(gl_, | |
2467 gl_->TexParameteri( | |
2468 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); | |
2469 GLC(gl_, gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); | |
2470 } else { | |
2471 mailbox = request->texture_mailbox().mailbox(); | |
2472 DCHECK_EQ(static_cast<unsigned>(GL_TEXTURE_2D), | |
2473 request->texture_mailbox().target()); | |
2474 DCHECK(!mailbox.IsZero()); | |
2475 unsigned incoming_sync_point = request->texture_mailbox().sync_point(); | |
2476 if (incoming_sync_point) | |
2477 GLC(gl_, gl_->WaitSyncPointCHROMIUM(incoming_sync_point)); | |
2478 | |
2479 texture_id = GLC( | |
2480 gl_, | |
2481 gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name)); | |
2482 } | |
2483 GetFramebufferTexture(texture_id, RGBA_8888, window_rect); | |
2484 | |
2485 unsigned sync_point = gl_->InsertSyncPointCHROMIUM(); | |
2486 TextureMailbox texture_mailbox(mailbox, GL_TEXTURE_2D, sync_point); | |
2487 | |
2488 scoped_ptr<SingleReleaseCallback> release_callback; | |
2489 if (own_mailbox) { | |
2490 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0)); | |
2491 release_callback = texture_mailbox_deleter_->GetReleaseCallback( | |
2492 output_surface_->context_provider(), texture_id); | |
2493 } else { | |
2494 gl_->DeleteTextures(1, &texture_id); | |
2495 } | |
2496 | |
2497 request->SendTextureResult( | |
2498 window_rect.size(), texture_mailbox, release_callback.Pass()); | |
2499 return; | |
2500 } | |
2501 | |
2502 DCHECK(request->force_bitmap_result()); | |
2503 | |
2504 scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels); | |
2505 pending_read->copy_request = request.Pass(); | |
2506 pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(), | |
2507 pending_read.Pass()); | |
2508 | |
2509 bool do_workaround = NeedsIOSurfaceReadbackWorkaround(); | |
2510 | |
2511 unsigned temporary_texture = 0; | |
2512 unsigned temporary_fbo = 0; | |
2513 | |
2514 if (do_workaround) { | |
2515 // On Mac OS X, calling glReadPixels() against an FBO whose color attachment | |
2516 // is an IOSurface-backed texture causes corruption of future glReadPixels() | |
2517 // calls, even those on different OpenGL contexts. It is believed that this | |
2518 // is the root cause of top crasher | |
2519 // http://crbug.com/99393. <rdar://problem/10949687> | |
2520 | |
2521 gl_->GenTextures(1, &temporary_texture); | |
2522 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, temporary_texture)); | |
2523 GLC(gl_, | |
2524 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | |
2525 GLC(gl_, | |
2526 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | |
2527 GLC(gl_, | |
2528 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); | |
2529 GLC(gl_, | |
2530 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); | |
2531 // Copy the contents of the current (IOSurface-backed) framebuffer into a | |
2532 // temporary texture. | |
2533 GetFramebufferTexture( | |
2534 temporary_texture, RGBA_8888, gfx::Rect(current_surface_size_)); | |
2535 gl_->GenFramebuffers(1, &temporary_fbo); | |
2536 // Attach this texture to an FBO, and perform the readback from that FBO. | |
2537 GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, temporary_fbo)); | |
2538 GLC(gl_, | |
2539 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, | |
2540 GL_COLOR_ATTACHMENT0, | |
2541 GL_TEXTURE_2D, | |
2542 temporary_texture, | |
2543 0)); | |
2544 | |
2545 DCHECK_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE), | |
2546 gl_->CheckFramebufferStatus(GL_FRAMEBUFFER)); | |
2547 } | |
2548 | |
2549 GLuint buffer = 0; | |
2550 gl_->GenBuffers(1, &buffer); | |
2551 GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, buffer)); | |
2552 GLC(gl_, | |
2553 gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, | |
2554 4 * window_rect.size().GetArea(), | |
2555 NULL, | |
2556 GL_STREAM_READ)); | |
2557 | |
2558 GLuint query = 0; | |
2559 gl_->GenQueriesEXT(1, &query); | |
2560 GLC(gl_, gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query)); | |
2561 | |
2562 GLC(gl_, | |
2563 gl_->ReadPixels(window_rect.x(), | |
2564 window_rect.y(), | |
2565 window_rect.width(), | |
2566 window_rect.height(), | |
2567 GL_RGBA, | |
2568 GL_UNSIGNED_BYTE, | |
2569 NULL)); | |
2570 | |
2571 GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0)); | |
2572 | |
2573 if (do_workaround) { | |
2574 // Clean up. | |
2575 GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, 0)); | |
2576 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0)); | |
2577 GLC(gl_, gl_->DeleteFramebuffers(1, &temporary_fbo)); | |
2578 GLC(gl_, gl_->DeleteTextures(1, &temporary_texture)); | |
2579 } | |
2580 | |
2581 base::Closure finished_callback = base::Bind(&GLRenderer::FinishedReadback, | |
2582 base::Unretained(this), | |
2583 buffer, | |
2584 query, | |
2585 window_rect.size()); | |
2586 // Save the finished_callback so it can be cancelled. | |
2587 pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset( | |
2588 finished_callback); | |
2589 base::Closure cancelable_callback = | |
2590 pending_async_read_pixels_.front()-> | |
2591 finished_read_pixels_callback.callback(); | |
2592 | |
2593 // Save the buffer to verify the callbacks happen in the expected order. | |
2594 pending_async_read_pixels_.front()->buffer = buffer; | |
2595 | |
2596 GLC(gl_, gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM)); | |
2597 context_support_->SignalQuery(query, cancelable_callback); | |
2598 | |
2599 EnforceMemoryPolicy(); | |
2600 } | |
2601 | |
2602 void GLRenderer::FinishedReadback(unsigned source_buffer, | |
2603 unsigned query, | |
2604 const gfx::Size& size) { | |
2605 DCHECK(!pending_async_read_pixels_.empty()); | |
2606 | |
2607 if (query != 0) { | |
2608 GLC(gl_, gl_->DeleteQueriesEXT(1, &query)); | |
2609 } | |
2610 | |
2611 PendingAsyncReadPixels* current_read = pending_async_read_pixels_.back(); | |
2612 // Make sure we service the readbacks in order. | |
2613 DCHECK_EQ(source_buffer, current_read->buffer); | |
2614 | |
2615 uint8* src_pixels = NULL; | |
2616 scoped_ptr<SkBitmap> bitmap; | |
2617 | |
2618 if (source_buffer != 0) { | |
2619 GLC(gl_, | |
2620 gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, source_buffer)); | |
2621 src_pixels = static_cast<uint8*>(gl_->MapBufferCHROMIUM( | |
2622 GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); | |
2623 | |
2624 if (src_pixels) { | |
2625 bitmap.reset(new SkBitmap); | |
2626 bitmap->allocN32Pixels(size.width(), size.height()); | |
2627 scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap)); | |
2628 uint8* dest_pixels = static_cast<uint8*>(bitmap->getPixels()); | |
2629 | |
2630 size_t row_bytes = size.width() * 4; | |
2631 int num_rows = size.height(); | |
2632 size_t total_bytes = num_rows * row_bytes; | |
2633 for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) { | |
2634 // Flip Y axis. | |
2635 size_t src_y = total_bytes - dest_y - row_bytes; | |
2636 // Swizzle OpenGL -> Skia byte order. | |
2637 for (size_t x = 0; x < row_bytes; x += 4) { | |
2638 dest_pixels[dest_y + x + SK_R32_SHIFT / 8] = | |
2639 src_pixels[src_y + x + 0]; | |
2640 dest_pixels[dest_y + x + SK_G32_SHIFT / 8] = | |
2641 src_pixels[src_y + x + 1]; | |
2642 dest_pixels[dest_y + x + SK_B32_SHIFT / 8] = | |
2643 src_pixels[src_y + x + 2]; | |
2644 dest_pixels[dest_y + x + SK_A32_SHIFT / 8] = | |
2645 src_pixels[src_y + x + 3]; | |
2646 } | |
2647 } | |
2648 | |
2649 GLC(gl_, | |
2650 gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM)); | |
2651 } | |
2652 GLC(gl_, gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0)); | |
2653 GLC(gl_, gl_->DeleteBuffers(1, &source_buffer)); | |
2654 } | |
2655 | |
2656 if (bitmap) | |
2657 current_read->copy_request->SendBitmapResult(bitmap.Pass()); | |
2658 pending_async_read_pixels_.pop_back(); | |
2659 } | |
2660 | |
2661 void GLRenderer::GetFramebufferTexture(unsigned texture_id, | |
2662 ResourceFormat texture_format, | |
2663 const gfx::Rect& window_rect) { | |
2664 DCHECK(texture_id); | |
2665 DCHECK_GE(window_rect.x(), 0); | |
2666 DCHECK_GE(window_rect.y(), 0); | |
2667 DCHECK_LE(window_rect.right(), current_surface_size_.width()); | |
2668 DCHECK_LE(window_rect.bottom(), current_surface_size_.height()); | |
2669 | |
2670 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id)); | |
2671 GLC(gl_, | |
2672 gl_->CopyTexImage2D(GL_TEXTURE_2D, | |
2673 0, | |
2674 GLDataFormat(texture_format), | |
2675 window_rect.x(), | |
2676 window_rect.y(), | |
2677 window_rect.width(), | |
2678 window_rect.height(), | |
2679 0)); | |
2680 GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, 0)); | |
2681 } | |
2682 | |
2683 bool GLRenderer::UseScopedTexture(DrawingFrame* frame, | |
2684 const ScopedResource* texture, | |
2685 const gfx::Rect& viewport_rect) { | |
2686 DCHECK(texture->id()); | |
2687 frame->current_render_pass = NULL; | |
2688 frame->current_texture = texture; | |
2689 | |
2690 return BindFramebufferToTexture(frame, texture, viewport_rect); | |
2691 } | |
2692 | |
2693 void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) { | |
2694 current_framebuffer_lock_ = nullptr; | |
2695 output_surface_->BindFramebuffer(); | |
2696 | |
2697 if (output_surface_->HasExternalStencilTest()) { | |
2698 SetStencilEnabled(true); | |
2699 GLC(gl_, gl_->StencilFunc(GL_EQUAL, 1, 1)); | |
2700 } else { | |
2701 SetStencilEnabled(false); | |
2702 } | |
2703 } | |
2704 | |
2705 bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame, | |
2706 const ScopedResource* texture, | |
2707 const gfx::Rect& target_rect) { | |
2708 DCHECK(texture->id()); | |
2709 | |
2710 // Explicitly release lock, otherwise we can crash when try to lock | |
2711 // same texture again. | |
2712 current_framebuffer_lock_ = nullptr; | |
2713 | |
2714 SetStencilEnabled(false); | |
2715 GLC(gl_, gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_)); | |
2716 current_framebuffer_lock_ = | |
2717 make_scoped_ptr(new ResourceProvider::ScopedWriteLockGL( | |
2718 resource_provider_, texture->id())); | |
2719 unsigned texture_id = current_framebuffer_lock_->texture_id(); | |
2720 GLC(gl_, | |
2721 gl_->FramebufferTexture2D( | |
2722 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0)); | |
2723 | |
2724 DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) == | |
2725 GL_FRAMEBUFFER_COMPLETE || | |
2726 IsContextLost()); | |
2727 return true; | |
2728 } | |
2729 | |
2730 void GLRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) { | |
2731 EnsureScissorTestEnabled(); | |
2732 | |
2733 // Don't unnecessarily ask the context to change the scissor, because it | |
2734 // may cause undesired GPU pipeline flushes. | |
2735 if (scissor_rect == scissor_rect_ && !scissor_rect_needs_reset_) | |
2736 return; | |
2737 | |
2738 scissor_rect_ = scissor_rect; | |
2739 FlushTextureQuadCache(SHARED_BINDING); | |
2740 GLC(gl_, | |
2741 gl_->Scissor(scissor_rect.x(), | |
2742 scissor_rect.y(), | |
2743 scissor_rect.width(), | |
2744 scissor_rect.height())); | |
2745 | |
2746 scissor_rect_needs_reset_ = false; | |
2747 } | |
2748 | |
2749 void GLRenderer::SetDrawViewport(const gfx::Rect& window_space_viewport) { | |
2750 viewport_ = window_space_viewport; | |
2751 GLC(gl_, | |
2752 gl_->Viewport(window_space_viewport.x(), | |
2753 window_space_viewport.y(), | |
2754 window_space_viewport.width(), | |
2755 window_space_viewport.height())); | |
2756 } | |
2757 | |
2758 void GLRenderer::InitializeSharedObjects() { | |
2759 TRACE_EVENT0("cc", "GLRenderer::InitializeSharedObjects"); | |
2760 | |
2761 // Create an FBO for doing offscreen rendering. | |
2762 GLC(gl_, gl_->GenFramebuffers(1, &offscreen_framebuffer_id_)); | |
2763 | |
2764 shared_geometry_ = | |
2765 make_scoped_ptr(new StaticGeometryBinding(gl_, QuadVertexRect())); | |
2766 clipped_geometry_ = make_scoped_ptr(new DynamicGeometryBinding(gl_)); | |
2767 } | |
2768 | |
2769 void GLRenderer::PrepareGeometry(BoundGeometry binding) { | |
2770 if (binding == bound_geometry_) { | |
2771 return; | |
2772 } | |
2773 | |
2774 switch (binding) { | |
2775 case SHARED_BINDING: | |
2776 shared_geometry_->PrepareForDraw(); | |
2777 break; | |
2778 case CLIPPED_BINDING: | |
2779 clipped_geometry_->PrepareForDraw(); | |
2780 break; | |
2781 case NO_BINDING: | |
2782 break; | |
2783 } | |
2784 bound_geometry_ = binding; | |
2785 } | |
2786 | |
2787 const GLRenderer::TileCheckerboardProgram* | |
2788 GLRenderer::GetTileCheckerboardProgram() { | |
2789 if (!tile_checkerboard_program_.initialized()) { | |
2790 TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize"); | |
2791 tile_checkerboard_program_.Initialize(output_surface_->context_provider(), | |
2792 TEX_COORD_PRECISION_NA, | |
2793 SAMPLER_TYPE_NA); | |
2794 } | |
2795 return &tile_checkerboard_program_; | |
2796 } | |
2797 | |
2798 const GLRenderer::DebugBorderProgram* GLRenderer::GetDebugBorderProgram() { | |
2799 if (!debug_border_program_.initialized()) { | |
2800 TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize"); | |
2801 debug_border_program_.Initialize(output_surface_->context_provider(), | |
2802 TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA); | |
2803 } | |
2804 return &debug_border_program_; | |
2805 } | |
2806 | |
2807 const GLRenderer::SolidColorProgram* GLRenderer::GetSolidColorProgram() { | |
2808 if (!solid_color_program_.initialized()) { | |
2809 TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize"); | |
2810 solid_color_program_.Initialize(output_surface_->context_provider(), | |
2811 TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA); | |
2812 } | |
2813 return &solid_color_program_; | |
2814 } | |
2815 | |
2816 const GLRenderer::SolidColorProgramAA* GLRenderer::GetSolidColorProgramAA() { | |
2817 if (!solid_color_program_aa_.initialized()) { | |
2818 TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize"); | |
2819 solid_color_program_aa_.Initialize(output_surface_->context_provider(), | |
2820 TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA); | |
2821 } | |
2822 return &solid_color_program_aa_; | |
2823 } | |
2824 | |
2825 const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram( | |
2826 TexCoordPrecision precision, | |
2827 BlendMode blend_mode) { | |
2828 DCHECK_GE(precision, 0); | |
2829 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2830 DCHECK_GE(blend_mode, 0); | |
2831 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2832 RenderPassProgram* program = &render_pass_program_[precision][blend_mode]; | |
2833 if (!program->initialized()) { | |
2834 TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize"); | |
2835 program->Initialize(output_surface_->context_provider(), precision, | |
2836 SAMPLER_TYPE_2D, blend_mode); | |
2837 } | |
2838 return program; | |
2839 } | |
2840 | |
2841 const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA( | |
2842 TexCoordPrecision precision, | |
2843 BlendMode blend_mode) { | |
2844 DCHECK_GE(precision, 0); | |
2845 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2846 DCHECK_GE(blend_mode, 0); | |
2847 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2848 RenderPassProgramAA* program = | |
2849 &render_pass_program_aa_[precision][blend_mode]; | |
2850 if (!program->initialized()) { | |
2851 TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize"); | |
2852 program->Initialize(output_surface_->context_provider(), precision, | |
2853 SAMPLER_TYPE_2D, blend_mode); | |
2854 } | |
2855 return program; | |
2856 } | |
2857 | |
2858 const GLRenderer::RenderPassMaskProgram* GLRenderer::GetRenderPassMaskProgram( | |
2859 TexCoordPrecision precision, | |
2860 SamplerType sampler, | |
2861 BlendMode blend_mode, | |
2862 bool mask_for_background) { | |
2863 DCHECK_GE(precision, 0); | |
2864 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2865 DCHECK_GE(sampler, 0); | |
2866 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
2867 DCHECK_GE(blend_mode, 0); | |
2868 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2869 RenderPassMaskProgram* program = | |
2870 &render_pass_mask_program_[precision][sampler][blend_mode] | |
2871 [mask_for_background ? HAS_MASK : NO_MASK]; | |
2872 if (!program->initialized()) { | |
2873 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize"); | |
2874 program->Initialize( | |
2875 output_surface_->context_provider(), precision, | |
2876 sampler, blend_mode, mask_for_background); | |
2877 } | |
2878 return program; | |
2879 } | |
2880 | |
2881 const GLRenderer::RenderPassMaskProgramAA* | |
2882 GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision, | |
2883 SamplerType sampler, | |
2884 BlendMode blend_mode, | |
2885 bool mask_for_background) { | |
2886 DCHECK_GE(precision, 0); | |
2887 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2888 DCHECK_GE(sampler, 0); | |
2889 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
2890 DCHECK_GE(blend_mode, 0); | |
2891 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2892 RenderPassMaskProgramAA* program = | |
2893 &render_pass_mask_program_aa_[precision][sampler][blend_mode] | |
2894 [mask_for_background ? HAS_MASK : NO_MASK]; | |
2895 if (!program->initialized()) { | |
2896 TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize"); | |
2897 program->Initialize( | |
2898 output_surface_->context_provider(), precision, | |
2899 sampler, blend_mode, mask_for_background); | |
2900 } | |
2901 return program; | |
2902 } | |
2903 | |
2904 const GLRenderer::RenderPassColorMatrixProgram* | |
2905 GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision, | |
2906 BlendMode blend_mode) { | |
2907 DCHECK_GE(precision, 0); | |
2908 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2909 DCHECK_GE(blend_mode, 0); | |
2910 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2911 RenderPassColorMatrixProgram* program = | |
2912 &render_pass_color_matrix_program_[precision][blend_mode]; | |
2913 if (!program->initialized()) { | |
2914 TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize"); | |
2915 program->Initialize(output_surface_->context_provider(), precision, | |
2916 SAMPLER_TYPE_2D, blend_mode); | |
2917 } | |
2918 return program; | |
2919 } | |
2920 | |
2921 const GLRenderer::RenderPassColorMatrixProgramAA* | |
2922 GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision, | |
2923 BlendMode blend_mode) { | |
2924 DCHECK_GE(precision, 0); | |
2925 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2926 DCHECK_GE(blend_mode, 0); | |
2927 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2928 RenderPassColorMatrixProgramAA* program = | |
2929 &render_pass_color_matrix_program_aa_[precision][blend_mode]; | |
2930 if (!program->initialized()) { | |
2931 TRACE_EVENT0("cc", | |
2932 "GLRenderer::renderPassColorMatrixProgramAA::initialize"); | |
2933 program->Initialize(output_surface_->context_provider(), precision, | |
2934 SAMPLER_TYPE_2D, blend_mode); | |
2935 } | |
2936 return program; | |
2937 } | |
2938 | |
2939 const GLRenderer::RenderPassMaskColorMatrixProgram* | |
2940 GLRenderer::GetRenderPassMaskColorMatrixProgram( | |
2941 TexCoordPrecision precision, | |
2942 SamplerType sampler, | |
2943 BlendMode blend_mode, | |
2944 bool mask_for_background) { | |
2945 DCHECK_GE(precision, 0); | |
2946 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2947 DCHECK_GE(sampler, 0); | |
2948 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
2949 DCHECK_GE(blend_mode, 0); | |
2950 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2951 RenderPassMaskColorMatrixProgram* program = | |
2952 &render_pass_mask_color_matrix_program_[precision][sampler][blend_mode] | |
2953 [mask_for_background ? HAS_MASK : NO_MASK]; | |
2954 if (!program->initialized()) { | |
2955 TRACE_EVENT0("cc", | |
2956 "GLRenderer::renderPassMaskColorMatrixProgram::initialize"); | |
2957 program->Initialize( | |
2958 output_surface_->context_provider(), precision, | |
2959 sampler, blend_mode, mask_for_background); | |
2960 } | |
2961 return program; | |
2962 } | |
2963 | |
2964 const GLRenderer::RenderPassMaskColorMatrixProgramAA* | |
2965 GLRenderer::GetRenderPassMaskColorMatrixProgramAA( | |
2966 TexCoordPrecision precision, | |
2967 SamplerType sampler, | |
2968 BlendMode blend_mode, | |
2969 bool mask_for_background) { | |
2970 DCHECK_GE(precision, 0); | |
2971 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2972 DCHECK_GE(sampler, 0); | |
2973 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
2974 DCHECK_GE(blend_mode, 0); | |
2975 DCHECK_LE(blend_mode, LAST_BLEND_MODE); | |
2976 RenderPassMaskColorMatrixProgramAA* program = | |
2977 &render_pass_mask_color_matrix_program_aa_[precision][sampler][blend_mode] | |
2978 [mask_for_background ? HAS_MASK : NO_MASK]; | |
2979 if (!program->initialized()) { | |
2980 TRACE_EVENT0("cc", | |
2981 "GLRenderer::renderPassMaskColorMatrixProgramAA::initialize"); | |
2982 program->Initialize( | |
2983 output_surface_->context_provider(), precision, | |
2984 sampler, blend_mode, mask_for_background); | |
2985 } | |
2986 return program; | |
2987 } | |
2988 | |
2989 const GLRenderer::TileProgram* GLRenderer::GetTileProgram( | |
2990 TexCoordPrecision precision, | |
2991 SamplerType sampler) { | |
2992 DCHECK_GE(precision, 0); | |
2993 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
2994 DCHECK_GE(sampler, 0); | |
2995 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
2996 TileProgram* program = &tile_program_[precision][sampler]; | |
2997 if (!program->initialized()) { | |
2998 TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize"); | |
2999 program->Initialize( | |
3000 output_surface_->context_provider(), precision, sampler); | |
3001 } | |
3002 return program; | |
3003 } | |
3004 | |
3005 const GLRenderer::TileProgramOpaque* GLRenderer::GetTileProgramOpaque( | |
3006 TexCoordPrecision precision, | |
3007 SamplerType sampler) { | |
3008 DCHECK_GE(precision, 0); | |
3009 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3010 DCHECK_GE(sampler, 0); | |
3011 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
3012 TileProgramOpaque* program = &tile_program_opaque_[precision][sampler]; | |
3013 if (!program->initialized()) { | |
3014 TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize"); | |
3015 program->Initialize( | |
3016 output_surface_->context_provider(), precision, sampler); | |
3017 } | |
3018 return program; | |
3019 } | |
3020 | |
3021 const GLRenderer::TileProgramAA* GLRenderer::GetTileProgramAA( | |
3022 TexCoordPrecision precision, | |
3023 SamplerType sampler) { | |
3024 DCHECK_GE(precision, 0); | |
3025 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3026 DCHECK_GE(sampler, 0); | |
3027 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
3028 TileProgramAA* program = &tile_program_aa_[precision][sampler]; | |
3029 if (!program->initialized()) { | |
3030 TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize"); | |
3031 program->Initialize( | |
3032 output_surface_->context_provider(), precision, sampler); | |
3033 } | |
3034 return program; | |
3035 } | |
3036 | |
3037 const GLRenderer::TileProgramSwizzle* GLRenderer::GetTileProgramSwizzle( | |
3038 TexCoordPrecision precision, | |
3039 SamplerType sampler) { | |
3040 DCHECK_GE(precision, 0); | |
3041 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3042 DCHECK_GE(sampler, 0); | |
3043 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
3044 TileProgramSwizzle* program = &tile_program_swizzle_[precision][sampler]; | |
3045 if (!program->initialized()) { | |
3046 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize"); | |
3047 program->Initialize( | |
3048 output_surface_->context_provider(), precision, sampler); | |
3049 } | |
3050 return program; | |
3051 } | |
3052 | |
3053 const GLRenderer::TileProgramSwizzleOpaque* | |
3054 GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision, | |
3055 SamplerType sampler) { | |
3056 DCHECK_GE(precision, 0); | |
3057 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3058 DCHECK_GE(sampler, 0); | |
3059 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
3060 TileProgramSwizzleOpaque* program = | |
3061 &tile_program_swizzle_opaque_[precision][sampler]; | |
3062 if (!program->initialized()) { | |
3063 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleOpaque::initialize"); | |
3064 program->Initialize( | |
3065 output_surface_->context_provider(), precision, sampler); | |
3066 } | |
3067 return program; | |
3068 } | |
3069 | |
3070 const GLRenderer::TileProgramSwizzleAA* GLRenderer::GetTileProgramSwizzleAA( | |
3071 TexCoordPrecision precision, | |
3072 SamplerType sampler) { | |
3073 DCHECK_GE(precision, 0); | |
3074 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3075 DCHECK_GE(sampler, 0); | |
3076 DCHECK_LE(sampler, LAST_SAMPLER_TYPE); | |
3077 TileProgramSwizzleAA* program = &tile_program_swizzle_aa_[precision][sampler]; | |
3078 if (!program->initialized()) { | |
3079 TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize"); | |
3080 program->Initialize( | |
3081 output_surface_->context_provider(), precision, sampler); | |
3082 } | |
3083 return program; | |
3084 } | |
3085 | |
3086 const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram( | |
3087 TexCoordPrecision precision) { | |
3088 DCHECK_GE(precision, 0); | |
3089 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3090 TextureProgram* program = &texture_program_[precision]; | |
3091 if (!program->initialized()) { | |
3092 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); | |
3093 program->Initialize(output_surface_->context_provider(), precision, | |
3094 SAMPLER_TYPE_2D); | |
3095 } | |
3096 return program; | |
3097 } | |
3098 | |
3099 const GLRenderer::NonPremultipliedTextureProgram* | |
3100 GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) { | |
3101 DCHECK_GE(precision, 0); | |
3102 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3103 NonPremultipliedTextureProgram* program = | |
3104 &nonpremultiplied_texture_program_[precision]; | |
3105 if (!program->initialized()) { | |
3106 TRACE_EVENT0("cc", | |
3107 "GLRenderer::NonPremultipliedTextureProgram::Initialize"); | |
3108 program->Initialize(output_surface_->context_provider(), precision, | |
3109 SAMPLER_TYPE_2D); | |
3110 } | |
3111 return program; | |
3112 } | |
3113 | |
3114 const GLRenderer::TextureBackgroundProgram* | |
3115 GLRenderer::GetTextureBackgroundProgram(TexCoordPrecision precision) { | |
3116 DCHECK_GE(precision, 0); | |
3117 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3118 TextureBackgroundProgram* program = &texture_background_program_[precision]; | |
3119 if (!program->initialized()) { | |
3120 TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize"); | |
3121 program->Initialize(output_surface_->context_provider(), precision, | |
3122 SAMPLER_TYPE_2D); | |
3123 } | |
3124 return program; | |
3125 } | |
3126 | |
3127 const GLRenderer::NonPremultipliedTextureBackgroundProgram* | |
3128 GLRenderer::GetNonPremultipliedTextureBackgroundProgram( | |
3129 TexCoordPrecision precision) { | |
3130 DCHECK_GE(precision, 0); | |
3131 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3132 NonPremultipliedTextureBackgroundProgram* program = | |
3133 &nonpremultiplied_texture_background_program_[precision]; | |
3134 if (!program->initialized()) { | |
3135 TRACE_EVENT0("cc", | |
3136 "GLRenderer::NonPremultipliedTextureProgram::Initialize"); | |
3137 program->Initialize(output_surface_->context_provider(), precision, | |
3138 SAMPLER_TYPE_2D); | |
3139 } | |
3140 return program; | |
3141 } | |
3142 | |
3143 const GLRenderer::TextureProgram* GLRenderer::GetTextureIOSurfaceProgram( | |
3144 TexCoordPrecision precision) { | |
3145 DCHECK_GE(precision, 0); | |
3146 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3147 TextureProgram* program = &texture_io_surface_program_[precision]; | |
3148 if (!program->initialized()) { | |
3149 TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize"); | |
3150 program->Initialize(output_surface_->context_provider(), precision, | |
3151 SAMPLER_TYPE_2D_RECT); | |
3152 } | |
3153 return program; | |
3154 } | |
3155 | |
3156 const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram( | |
3157 TexCoordPrecision precision) { | |
3158 DCHECK_GE(precision, 0); | |
3159 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3160 VideoYUVProgram* program = &video_yuv_program_[precision]; | |
3161 if (!program->initialized()) { | |
3162 TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize"); | |
3163 program->Initialize(output_surface_->context_provider(), precision, | |
3164 SAMPLER_TYPE_2D); | |
3165 } | |
3166 return program; | |
3167 } | |
3168 | |
3169 const GLRenderer::VideoYUVAProgram* GLRenderer::GetVideoYUVAProgram( | |
3170 TexCoordPrecision precision) { | |
3171 DCHECK_GE(precision, 0); | |
3172 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3173 VideoYUVAProgram* program = &video_yuva_program_[precision]; | |
3174 if (!program->initialized()) { | |
3175 TRACE_EVENT0("cc", "GLRenderer::videoYUVAProgram::initialize"); | |
3176 program->Initialize(output_surface_->context_provider(), precision, | |
3177 SAMPLER_TYPE_2D); | |
3178 } | |
3179 return program; | |
3180 } | |
3181 | |
3182 const GLRenderer::VideoStreamTextureProgram* | |
3183 GLRenderer::GetVideoStreamTextureProgram(TexCoordPrecision precision) { | |
3184 if (!Capabilities().using_egl_image) | |
3185 return NULL; | |
3186 DCHECK_GE(precision, 0); | |
3187 DCHECK_LE(precision, LAST_TEX_COORD_PRECISION); | |
3188 VideoStreamTextureProgram* program = | |
3189 &video_stream_texture_program_[precision]; | |
3190 if (!program->initialized()) { | |
3191 TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize"); | |
3192 program->Initialize(output_surface_->context_provider(), precision, | |
3193 SAMPLER_TYPE_EXTERNAL_OES); | |
3194 } | |
3195 return program; | |
3196 } | |
3197 | |
3198 void GLRenderer::CleanupSharedObjects() { | |
3199 shared_geometry_ = nullptr; | |
3200 | |
3201 for (int i = 0; i <= LAST_TEX_COORD_PRECISION; ++i) { | |
3202 for (int j = 0; j <= LAST_SAMPLER_TYPE; ++j) { | |
3203 tile_program_[i][j].Cleanup(gl_); | |
3204 tile_program_opaque_[i][j].Cleanup(gl_); | |
3205 tile_program_swizzle_[i][j].Cleanup(gl_); | |
3206 tile_program_swizzle_opaque_[i][j].Cleanup(gl_); | |
3207 tile_program_aa_[i][j].Cleanup(gl_); | |
3208 tile_program_swizzle_aa_[i][j].Cleanup(gl_); | |
3209 | |
3210 for (int k = 0; k <= LAST_BLEND_MODE; k++) { | |
3211 for (int l = 0; l <= LAST_MASK_VALUE; ++l) { | |
3212 render_pass_mask_program_[i][j][k][l].Cleanup(gl_); | |
3213 render_pass_mask_program_aa_[i][j][k][l].Cleanup(gl_); | |
3214 render_pass_mask_color_matrix_program_aa_[i][j][k][l].Cleanup(gl_); | |
3215 render_pass_mask_color_matrix_program_[i][j][k][l].Cleanup(gl_); | |
3216 } | |
3217 } | |
3218 } | |
3219 for (int j = 0; j <= LAST_BLEND_MODE; j++) { | |
3220 render_pass_program_[i][j].Cleanup(gl_); | |
3221 render_pass_program_aa_[i][j].Cleanup(gl_); | |
3222 render_pass_color_matrix_program_[i][j].Cleanup(gl_); | |
3223 render_pass_color_matrix_program_aa_[i][j].Cleanup(gl_); | |
3224 } | |
3225 | |
3226 texture_program_[i].Cleanup(gl_); | |
3227 nonpremultiplied_texture_program_[i].Cleanup(gl_); | |
3228 texture_background_program_[i].Cleanup(gl_); | |
3229 nonpremultiplied_texture_background_program_[i].Cleanup(gl_); | |
3230 texture_io_surface_program_[i].Cleanup(gl_); | |
3231 | |
3232 video_yuv_program_[i].Cleanup(gl_); | |
3233 video_yuva_program_[i].Cleanup(gl_); | |
3234 video_stream_texture_program_[i].Cleanup(gl_); | |
3235 } | |
3236 | |
3237 tile_checkerboard_program_.Cleanup(gl_); | |
3238 | |
3239 debug_border_program_.Cleanup(gl_); | |
3240 solid_color_program_.Cleanup(gl_); | |
3241 solid_color_program_aa_.Cleanup(gl_); | |
3242 | |
3243 if (offscreen_framebuffer_id_) | |
3244 GLC(gl_, gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_)); | |
3245 | |
3246 if (on_demand_tile_raster_resource_id_) | |
3247 resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_); | |
3248 | |
3249 ReleaseRenderPassTextures(); | |
3250 } | |
3251 | |
3252 void GLRenderer::ReinitializeGLState() { | |
3253 is_scissor_enabled_ = false; | |
3254 scissor_rect_needs_reset_ = true; | |
3255 stencil_shadow_ = false; | |
3256 blend_shadow_ = true; | |
3257 program_shadow_ = 0; | |
3258 | |
3259 RestoreGLState(); | |
3260 } | |
3261 | |
3262 void GLRenderer::RestoreGLState() { | |
3263 // This restores the current GLRenderer state to the GL context. | |
3264 bound_geometry_ = NO_BINDING; | |
3265 PrepareGeometry(SHARED_BINDING); | |
3266 | |
3267 GLC(gl_, gl_->Disable(GL_DEPTH_TEST)); | |
3268 GLC(gl_, gl_->Disable(GL_CULL_FACE)); | |
3269 GLC(gl_, gl_->ColorMask(true, true, true, true)); | |
3270 GLC(gl_, gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); | |
3271 GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0)); | |
3272 | |
3273 if (program_shadow_) | |
3274 gl_->UseProgram(program_shadow_); | |
3275 | |
3276 if (stencil_shadow_) | |
3277 GLC(gl_, gl_->Enable(GL_STENCIL_TEST)); | |
3278 else | |
3279 GLC(gl_, gl_->Disable(GL_STENCIL_TEST)); | |
3280 | |
3281 if (blend_shadow_) | |
3282 GLC(gl_, gl_->Enable(GL_BLEND)); | |
3283 else | |
3284 GLC(gl_, gl_->Disable(GL_BLEND)); | |
3285 | |
3286 if (is_scissor_enabled_) { | |
3287 GLC(gl_, gl_->Enable(GL_SCISSOR_TEST)); | |
3288 GLC(gl_, | |
3289 gl_->Scissor(scissor_rect_.x(), | |
3290 scissor_rect_.y(), | |
3291 scissor_rect_.width(), | |
3292 scissor_rect_.height())); | |
3293 } else { | |
3294 GLC(gl_, gl_->Disable(GL_SCISSOR_TEST)); | |
3295 } | |
3296 } | |
3297 | |
3298 void GLRenderer::RestoreFramebuffer(DrawingFrame* frame) { | |
3299 UseRenderPass(frame, frame->current_render_pass); | |
3300 } | |
3301 | |
3302 bool GLRenderer::IsContextLost() { | |
3303 return output_surface_->context_provider()->IsContextLost(); | |
3304 } | |
3305 | |
3306 void GLRenderer::ScheduleOverlays(DrawingFrame* frame) { | |
3307 if (!frame->overlay_list.size()) | |
3308 return; | |
3309 | |
3310 ResourceProvider::ResourceIdArray resources; | |
3311 OverlayCandidateList& overlays = frame->overlay_list; | |
3312 OverlayCandidateList::iterator it; | |
3313 for (it = overlays.begin(); it != overlays.end(); ++it) { | |
3314 const OverlayCandidate& overlay = *it; | |
3315 // Skip primary plane. | |
3316 if (overlay.plane_z_order == 0) | |
3317 continue; | |
3318 | |
3319 pending_overlay_resources_.push_back( | |
3320 make_scoped_ptr(new ResourceProvider::ScopedReadLockGL( | |
3321 resource_provider_, overlay.resource_id))); | |
3322 | |
3323 context_support_->ScheduleOverlayPlane( | |
3324 overlay.plane_z_order, | |
3325 overlay.transform, | |
3326 pending_overlay_resources_.back()->texture_id(), | |
3327 overlay.display_rect, | |
3328 overlay.uv_rect); | |
3329 } | |
3330 } | |
3331 | |
3332 } // namespace cc | |
OLD | NEW |