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 |