Index: cc/output/gl_renderer.cc |
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc |
index e760ac03ddb993757836e4eac9b1899367c084ec..a7f409e79b36dfd234d0faff1d5a8e676667148f 100644 |
--- a/cc/output/gl_renderer.cc |
+++ b/cc/output/gl_renderer.cc |
@@ -160,11 +160,11 @@ struct DrawRenderPassDrawQuadParams { |
const Resource* contents_texture = nullptr; |
const gfx::QuadF* clip_region = nullptr; |
bool flip_texture = false; |
- |
gfx::Transform window_matrix; |
gfx::Transform projection_matrix; |
+ gfx::Transform quad_to_target_transform; |
- // |frame| is needed for background effects. |
+ // |frame| is only used for background effects. |
DirectRenderer::DrawingFrame* frame = nullptr; |
// Whether the texture to be sampled from needs to be flipped. |
@@ -215,6 +215,7 @@ struct DrawRenderPassDrawQuadParams { |
bool use_color_matrix = false; |
gfx::QuadF surface_quad; |
+ |
gfx::Transform contents_device_transform; |
}; |
@@ -1068,6 +1069,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame, |
void GLRenderer::DrawRenderPassQuadInternal( |
DrawRenderPassDrawQuadParams* params) { |
+ params->quad_to_target_transform = |
+ params->quad->shared_quad_state->quad_to_target_transform; |
if (!InitializeRPDQParameters(params)) |
return; |
UpdateRPDQShadersForBlending(params); |
@@ -1093,8 +1096,7 @@ bool GLRenderer::InitializeRPDQParameters( |
static_cast<float>(dst_rect.width()), |
static_cast<float>(dst_rect.height())); |
gfx::Transform quad_rect_matrix; |
- QuadRectTransform(&quad_rect_matrix, |
- quad->shared_quad_state->quad_to_target_transform, |
+ QuadRectTransform(&quad_rect_matrix, params->quad_to_target_transform, |
params->dst_rect); |
params->contents_device_transform = |
params->window_matrix * params->projection_matrix * quad_rect_matrix; |
@@ -1217,8 +1219,7 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters( |
if (clip_rect.IsEmpty()) { |
clip_rect = current_draw_rect_; |
} |
- gfx::Transform transform = |
- quad->shared_quad_state->quad_to_target_transform; |
+ gfx::Transform transform = params->quad_to_target_transform; |
gfx::QuadF clip_quad = gfx::QuadF(gfx::RectF(clip_rect)); |
gfx::QuadF local_clip = MapQuadToLocalSpace(transform, clip_quad); |
params->dst_rect.Intersect(local_clip.BoundingBox()); |
@@ -1499,8 +1500,7 @@ void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) { |
} |
void GLRenderer::DrawRPDQ(const DrawRenderPassDrawQuadParams& params) { |
- DrawQuadGeometry(params.projection_matrix, |
- params.quad->shared_quad_state->quad_to_target_transform, |
+ DrawQuadGeometry(params.projection_matrix, params.quad_to_target_transform, |
params.dst_rect, params.locations.matrix); |
// Flush the compositor context before the filter bitmap goes out of |
@@ -2728,6 +2728,8 @@ void GLRenderer::FinishDrawingQuadList() { |
} |
bool GLRenderer::FlippedFramebuffer(const DrawingFrame* frame) const { |
+ if (frame == force_drawing_frame_framebuffer_flipped_) |
+ return true; |
if (frame->current_render_pass != frame->root_render_pass) |
return true; |
return FlippedRootFramebuffer(); |
@@ -3777,10 +3779,11 @@ void GLRenderer::ScheduleCALayers(DrawingFrame* frame) { |
scoped_refptr<CALayerOverlaySharedState> shared_state; |
size_t copied_render_pass_count = 0; |
for (const CALayerOverlay& ca_layer_overlay : frame->ca_layer_overlay_list) { |
- if (!overlay_resource_pool_) { |
- overlay_resource_pool_ = ResourcePool::CreateForGpuMemoryBufferResources( |
- resource_provider_, base::ThreadTaskRunnerHandle::Get().get(), |
- gfx::BufferUsage::SCANOUT); |
+ if (ca_layer_overlay.rpdq) { |
+ ScheduleRenderPassDrawQuad(&ca_layer_overlay, frame); |
+ shared_state = nullptr; |
+ ++copied_render_pass_count; |
+ continue; |
} |
ResourceId contents_resource_id = ca_layer_overlay.contents_resource_id; |
@@ -3854,4 +3857,161 @@ void GLRenderer::ScheduleOverlays(DrawingFrame* frame) { |
} |
} |
+// This function draws the RenderPassDrawQuad into a temporary |
+// texture/framebuffer, and then copies the result into an IOSurface. The |
+// inefficient (but simple) way to do this would be to: |
+// 1. Allocate a framebuffer the size of the screen. |
+// 2. Draw using all the normal RPDQ draw logic. |
+// Instead, this method does the following: |
+// 1. Configure parameters as if drawing to a framebuffer the size of the |
+// screen. This reuses most of the RPDQ draw logic. |
+// 2. Update parameters to draw into a framebuffer only as large as needed. |
+// 3. Fix shader uniforms that were broken by (2). |
+// |
+// Then: |
+// 4. Allocate a temporary TEXTURE_2D as the drawing destination. |
+// 5. Draw the RPDQ. |
+// 6. Copy from the temporary texture into an IOSurface. |
+void GLRenderer::CopyRenderPassDrawQuadToOverlayResource( |
+ const CALayerOverlay* ca_layer_overlay, |
+ Resource** resource, |
+ DrawingFrame* external_frame, |
+ gfx::RectF* new_bounds) { |
+ ScopedResource* contents_texture = |
+ render_pass_textures_[ca_layer_overlay->rpdq->render_pass_id].get(); |
+ DCHECK(contents_texture); |
+ |
+ // Configure parameters as if drawing to a framebuffer the size of the |
+ // screen. |
+ DrawRenderPassDrawQuadParams params; |
+ params.quad = ca_layer_overlay->rpdq; |
+ params.flip_texture = false; |
+ params.contents_texture = contents_texture; |
+ params.quad_to_target_transform = |
+ params.quad->shared_quad_state->quad_to_target_transform; |
+ |
+ // Calculate projection and window matrices using InitializeViewport(). This |
+ // requires creating a dummy DrawingFrame. |
+ { |
+ DrawingFrame frame; |
+ gfx::Rect frame_rect = external_frame->device_viewport_rect; |
+ force_drawing_frame_framebuffer_flipped_ = &frame; |
+ InitializeViewport(&frame, frame_rect, frame_rect, frame_rect.size()); |
+ force_drawing_frame_framebuffer_flipped_ = nullptr; |
+ params.projection_matrix = frame.projection_matrix; |
+ params.window_matrix = frame.window_matrix; |
+ } |
+ |
+ // Perform basic initialization with the screen-sized viewport. |
+ if (!InitializeRPDQParameters(¶ms)) |
+ return; |
+ if (!UpdateRPDQWithSkiaFilters(¶ms)) |
+ return; |
+ |
+ // Compute the rect that encloses the image of the quad in the viewport. |
+ gfx::Rect quad_image_rect; |
+ gfx::RectF quad_image_rectf; |
+ { |
+ gfx::RectF dst_rect_image = params.dst_rect; |
+ params.quad_to_target_transform.TransformRect(&dst_rect_image); |
+ quad_image_rect = gfx::ToEnclosingRect(dst_rect_image); |
+ quad_image_rectf = gfx::RectF(quad_image_rect); |
+ } |
+ *new_bounds = gfx::RectF(quad_image_rect); |
+ |
+ // Create in *resource an overlay-capable resource the size of that rect, and |
+ // bind it to a temporary framebuffer. |
+ *resource = overlay_resource_pool_->AcquireResource( |
+ quad_image_rect.size(), ResourceFormat::RGBA_8888); |
+ ResourceProvider::ScopedWriteLockGL destination(resource_provider_, |
+ (*resource)->id(), false); |
+ GLuint temp_fbo = 0; |
+ gl_->GenFramebuffers(1, &temp_fbo); |
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo); |
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
+ destination.target(), destination.texture_id(), 0); |
+ DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) == |
+ GL_FRAMEBUFFER_COMPLETE); |
+ gl_->ClearColor(0, 0, 0, 0); |
+ gl_->Clear(GL_COLOR_BUFFER_BIT); |
+ |
+ // Note that it is necessary to set up the samplers here, after *resource has |
+ // been created, because resource creation will dirty texture binding state. |
+ UpdateRPDQTexturesForSampling(¶ms); |
+ UpdateRPDQBlendMode(¶ms); |
+ ChooseRPDQProgram(¶ms); |
+ UpdateRPDQUniforms(¶ms); |
+ |
+ // Set the viewport to be that image rect, moved to be at the origin. |
+ gl_->Viewport(0, 0, quad_image_rect.width(), quad_image_rect.height()); |
+ |
+ // Update the RPDQ's transforms and viewport so that the image of the quad |
+ // will be the new viewport. |
+ params.projection_matrix.matrix().preScale( |
+ current_window_space_viewport_.width() / quad_image_rectf.width(), |
+ current_window_space_viewport_.height() / quad_image_rectf.height(), 1); |
+ params.quad_to_target_transform.matrix().postTranslate( |
+ -quad_image_rect.x(), -quad_image_rect.y(), 0); |
+ |
+ // Draw the quad into *resource. |
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo); |
+ DrawRPDQ(params); |
+ gl_->DeleteFramebuffers(1, &temp_fbo); |
+} |
+ |
+void GLRenderer::ScheduleRenderPassDrawQuad( |
+ const CALayerOverlay* ca_layer_overlay, |
+ DrawingFrame* external_frame) { |
+ DCHECK(ca_layer_overlay->rpdq); |
+ |
+ if (!overlay_resource_pool_) { |
+ overlay_resource_pool_ = ResourcePool::CreateForGpuMemoryBufferResources( |
+ resource_provider_, base::ThreadTaskRunnerHandle::Get().get(), |
+ gfx::BufferUsage::SCANOUT); |
+ } |
+ |
+ Resource* resource = nullptr; |
+ gfx::RectF new_bounds; |
+ CopyRenderPassDrawQuadToOverlayResource(ca_layer_overlay, &resource, |
+ external_frame, &new_bounds); |
+ if (!resource || !resource->id()) |
+ return; |
+ |
+ pending_overlay_resources_.push_back( |
+ base::WrapUnique(new ResourceProvider::ScopedReadLockGL( |
+ resource_provider_, resource->id()))); |
+ unsigned texture_id = pending_overlay_resources_.back()->texture_id(); |
+ |
+ // Once a resource is released, it is marked as "busy". It will be |
+ // available for reuse after the ScopedReadLockGL is destroyed. |
+ overlay_resource_pool_->ReleaseResource(resource); |
+ |
+ GLfloat contents_rect[4] = { |
+ ca_layer_overlay->contents_rect.x(), ca_layer_overlay->contents_rect.y(), |
+ ca_layer_overlay->contents_rect.width(), |
+ ca_layer_overlay->contents_rect.height(), |
+ }; |
+ GLfloat bounds_rect[4] = { |
+ new_bounds.x(), new_bounds.y(), new_bounds.width(), new_bounds.height(), |
+ }; |
+ GLboolean is_clipped = ca_layer_overlay->shared_state->is_clipped; |
+ GLfloat clip_rect[4] = {ca_layer_overlay->shared_state->clip_rect.x(), |
+ ca_layer_overlay->shared_state->clip_rect.y(), |
+ ca_layer_overlay->shared_state->clip_rect.width(), |
+ ca_layer_overlay->shared_state->clip_rect.height()}; |
+ GLint sorting_context_id = ca_layer_overlay->shared_state->sorting_context_id; |
+ DCHECK_EQ(0, sorting_context_id); |
+ SkMatrix44 transform; |
+ GLfloat gl_transform[16]; |
+ transform.asColMajorf(gl_transform); |
+ unsigned filter = ca_layer_overlay->filter; |
+ |
+ gl_->ScheduleCALayerSharedStateCHROMIUM( |
+ ca_layer_overlay->shared_state->opacity, is_clipped, clip_rect, |
+ sorting_context_id, gl_transform); |
+ gl_->ScheduleCALayerCHROMIUM( |
+ texture_id, contents_rect, ca_layer_overlay->background_color, |
+ ca_layer_overlay->edge_aa_mask, bounds_rect, filter); |
+} |
+ |
} // namespace cc |