Chromium Code Reviews| Index: cc/output/gl_renderer.cc |
| diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc |
| index bc635b52a43e3b78af8e14d53e392316a0ff0d57..2dcfc10c1d0bf3f97eabce6d1f73db0ad5c9f2ec 100644 |
| --- a/cc/output/gl_renderer.cc |
| +++ b/cc/output/gl_renderer.cc |
| @@ -67,6 +67,28 @@ using gpu::gles2::GLES2Interface; |
| namespace cc { |
| namespace { |
| +class ScopedTextureDeleter { |
| + public: |
| + ScopedTextureDeleter(GLuint texture, gpu::gles2::GLES2Interface* gl) |
| + : texture_(texture), gl_(gl) {} |
| + ~ScopedTextureDeleter() { gl_->DeleteTextures(1, &texture_); } |
| + |
| + private: |
| + GLuint texture_; |
| + gpu::gles2::GLES2Interface* gl_; |
| +}; |
| + |
| +class ScopedFramebufferDeleter { |
| + public: |
| + ScopedFramebufferDeleter(GLuint fbo, gpu::gles2::GLES2Interface* gl) |
| + : fbo_(fbo), gl_(gl) {} |
| + ~ScopedFramebufferDeleter() { gl_->DeleteFramebuffers(1, &fbo_); } |
| + |
| + private: |
| + GLuint fbo_; |
| + gpu::gles2::GLES2Interface* gl_; |
| +}; |
| + |
| Float4 UVTransform(const TextureDrawQuad* quad) { |
| gfx::PointF uv0 = quad->uv_top_left; |
| gfx::PointF uv1 = quad->uv_bottom_right; |
| @@ -165,7 +187,8 @@ struct DrawRenderPassDrawQuadParams { |
| gfx::Transform window_matrix; |
| gfx::Transform projection_matrix; |
| - // |frame| is needed for background effects. |
| + // |frame| is used to restore the current render pass. |frame| is also needed |
| + // for background effects. If |frame| is not present, nothing happens. |
| DirectRenderer::DrawingFrame* frame = nullptr; |
| // Whether the texture to be sampled from needs to be flipped. |
| @@ -2697,6 +2720,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(); |
| @@ -3745,7 +3770,7 @@ bool GLRenderer::IsContextLost() { |
| 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) { |
| + for (CALayerOverlay& ca_layer_overlay : frame->ca_layer_overlay_list) { |
| if (!overlay_resource_pool_) { |
| overlay_resource_pool_ = ResourcePool::CreateForGpuMemoryBufferResources( |
| resource_provider_, base::ThreadTaskRunnerHandle::Get().get(), |
| @@ -3755,11 +3780,13 @@ void GLRenderer::ScheduleCALayers(DrawingFrame* frame) { |
| ResourceId contents_resource_id = ca_layer_overlay.contents_resource_id; |
| Resource* resource = nullptr; |
| // Some CALayers require a final round of processing. |
| - if (ca_layer_overlay.render_pass_id.IsValid()) { |
| - CopyRenderPassToOverlayResource(ca_layer_overlay.render_pass_id, |
| - &resource); |
| - contents_resource_id = resource->id(); |
| - ++copied_render_pass_count; |
| + if (ca_layer_overlay.rpdq.get()) { |
| + CopyRenderPassDrawQuadToOverlayResource(&ca_layer_overlay, &resource, |
| + frame); |
|
ccameron
2016/08/04 01:46:01
Rather than updating the CALayerOverlay parameters
erikchen
2016/08/05 17:15:06
Done.
|
| + if (resource) { |
| + contents_resource_id = resource->id(); |
| + ++copied_render_pass_count; |
| + } |
| } |
| unsigned texture_id = 0; |
| @@ -3820,7 +3847,11 @@ void GLRenderer::ScheduleCALayers(DrawingFrame* frame) { |
| static_cast<GLuint>(filter_effect.drop_shadow_color); |
| } |
| - gl_->ScheduleCALayerFilterEffectsCHROMIUM(effects.size(), effects.data()); |
| + // TODO(erikchen): Remove all logic associated with |
| + // ScheduleCALayerFilterEffectsCHROMIUM once the implementation of filter |
| + // effects for CA is fully functional. https://crbug.com/581526. |
| + // gl_->ScheduleCALayerFilterEffectsCHROMIUM(effects.size(), |
| + // effects.data()); |
| } |
| gl_->ScheduleCALayerCHROMIUM( |
| texture_id, contents_rect, ca_layer_overlay.background_color, |
| @@ -3886,4 +3917,137 @@ void GLRenderer::CopyRenderPassToOverlayResource( |
| GL_FALSE, GL_FALSE); |
| } |
| +// This function draws the RenderPassDrawQuad into a temporary |
| +// texture/framebuffer, and then copies the result into an IOSurface. |
| +void GLRenderer::CopyRenderPassDrawQuadToOverlayResource( |
| + CALayerOverlay* ca_layer_overlay, |
| + Resource** resource, |
| + DrawingFrame* external_frame) { |
| + ScopedResource* contents_texture = |
| + render_pass_textures_[ca_layer_overlay->rpdq->render_pass_id].get(); |
| + DCHECK(contents_texture); |
| + |
| + // The intermediary texture may need to be larger than the original content, |
| + // since the BLUR and DROP_SHADOW filter effects affect pixels outside the |
| + // original content. The exact size is computed within Skia, along with the |
| + // creation of |filter_image|. That computation requires that the |dst_rect| |
| + // parameter be configured. |
| + DrawRenderPassDrawQuadParams params; |
| + params.quad = ca_layer_overlay->rpdq.get(); |
| + params.flip_texture = true; |
| + params.contents_texture = contents_texture; |
| + |
| + SkMatrix scale_matrix; |
| + scale_matrix.setScale(params.quad->filters_scale.x(), |
| + params.quad->filters_scale.y()); |
| + gfx::Rect dst_rect = |
| + params.quad->filters.MapRect(params.quad->rect, scale_matrix); |
| + params.dst_rect.SetRect(static_cast<float>(dst_rect.x()), |
| + static_cast<float>(dst_rect.y()), |
| + static_cast<float>(dst_rect.width()), |
| + static_cast<float>(dst_rect.height())); |
| + |
| + if (!UpdateRPDQWithSkiaFilters(¶ms)) { |
| + return; |
| + } |
| + |
| + // |params.dst_rect| and |params.src_offset| now contain values that reflect a |
| + // potentially increased-size content area. |
| + gfx::RectF updated_dst_rect = params.dst_rect; |
| + gfx::Point updated_src_offset = params.src_offset; |
| + |
| + // Establish temp texture and fbo. |
| + GLuint temp_texture; |
| + GLuint temp_fbo; |
| + |
| + gl_->GenTextures(1, &temp_texture); |
| + ScopedTextureDeleter texture_deleter(temp_texture, gl_); |
| + gl_->BindTexture(GL_TEXTURE_2D, temp_texture); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, updated_dst_rect.width(), |
| + updated_dst_rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + nullptr); |
| + |
| + gl_->GenFramebuffers(1, &temp_fbo); |
| + ScopedFramebufferDeleter framebuffer_deleter(temp_fbo, gl_); |
| + gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo); |
| + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| + temp_texture, 0); |
| + DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) == |
| + GL_FRAMEBUFFER_COMPLETE); |
| + |
| + // Clear to 0 to ensure the background is transparent. |
| + gl_->ClearColor(0, 0, 0, 0); |
| + gl_->Clear(GL_COLOR_BUFFER_BIT); |
| + |
| + // Set up a new drawing context. The viewport should be the same size as |
| + // |temp_fbo|. Update the viewport using InitializeViewport(). This requires |
| + // creating a dummy DrawingFrame. This also calculates the projection and |
| + // window matrices. |
| + DrawingFrame frame; |
| + force_drawing_frame_framebuffer_flipped_ = &frame; |
| + gfx::Rect frame_rect = |
| + gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height()); |
| + InitializeViewport(&frame, frame_rect, frame_rect, frame_rect.size()); |
| + force_drawing_frame_framebuffer_flipped_ = nullptr; |
| + SetViewport(); |
| + params.projection_matrix = frame.projection_matrix; |
| + params.window_matrix = frame.window_matrix; |
| + |
| + // The SharedQuadState for the RenderPassDrawQuad needs to be updated to |
| + // reflect the new viewport. |
| + SharedQuadState sqs = *(ca_layer_overlay->rpdq->shared_quad_state); |
| + ca_layer_overlay->rpdq->shared_quad_state = &sqs; |
| + sqs.quad_to_target_transform = gfx::Transform(); |
| + sqs.quad_to_target_transform.Translate(-updated_dst_rect.x(), |
| + -updated_dst_rect.y()); |
| + |
| + // Perform basic initialization in the new viewport. |
| + if (!InitializeRPDQParameters(¶ms)) |
| + return; |
| + |
| + // Update |dst_rect| and |src_offset| with the values originally calculated |
| + // from Skia. |
| + params.dst_rect = updated_dst_rect; |
| + params.src_offset = updated_src_offset; |
| + |
| + UpdateRPDQTexturesForSampling(¶ms); |
| + UpdateRPDQBlendMode(¶ms); |
| + ChooseRPDQProgram(¶ms); |
| + UpdateRPDQUniforms(¶ms); |
| + |
| + // Prior to drawing, set up the destination framebuffer. |
| + gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo); |
| + DrawRPDQ(params); |
|
ccameron
2016/08/04 01:46:01
I'll need to understand this a bit better, but, my
erikchen
2016/08/05 17:15:06
Your suggestion is sound. The new PS implements yo
|
| + |
| + // Copy from the temporary framebuffer into an overlay. |
| + *resource = overlay_resource_pool_->AcquireResource( |
| + gfx::Size(updated_dst_rect.width(), updated_dst_rect.height()), |
| + ResourceFormat::RGBA_8888); |
| + ResourceProvider::ScopedWriteLockGL destination(resource_provider_, |
| + (*resource)->id(), false); |
| + gl_->CopySubTextureCHROMIUM(temp_texture, destination.texture_id(), 0, 0, 0, |
| + 0, updated_dst_rect.width(), |
| + updated_dst_rect.height(), GL_TRUE, GL_FALSE, |
| + GL_FALSE); |
| + |
| + // Update the CALayerOverlaySharedState to reflect the new size and translate |
| + // of the overlay. |
| + ca_layer_overlay->bounds_rect = |
| + gfx::RectF(0, 0, updated_dst_rect.width(), updated_dst_rect.height()); |
| + scoped_refptr<CALayerOverlaySharedState> shared_state = |
| + (new CALayerOverlaySharedState); |
| + *shared_state = *ca_layer_overlay->shared_state; |
| + ca_layer_overlay->shared_state = shared_state; |
|
ccameron
2016/08/04 01:46:01
This doesn't strike me as correct. What if shared_
erikchen
2016/08/05 17:15:06
Right. This should have been preTranslate.
|
| + float x_translate = shared_state->transform.getFloat(0, 3); |
| + float y_translate = shared_state->transform.getFloat(1, 3); |
| + float z_translate = shared_state->transform.getFloat(2, 3); |
| + shared_state->transform.setTranslate(x_translate + updated_dst_rect.x(), |
| + y_translate + updated_dst_rect.y(), |
| + z_translate); |
| +} |
| + |
| } // namespace cc |