| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/layers/io_surface_layer_impl.h" |
| |
| #include "base/strings/stringprintf.h" |
| #include "cc/layers/quad_sink.h" |
| #include "cc/output/gl_renderer.h" // For the GLC() macro. |
| #include "cc/output/output_surface.h" |
| #include "cc/quads/io_surface_draw_quad.h" |
| #include "cc/trees/layer_tree_impl.h" |
| #include "gpu/GLES2/gl2extchromium.h" |
| #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" |
| #include "third_party/khronos/GLES2/gl2.h" |
| #include "third_party/khronos/GLES2/gl2ext.h" |
| |
| namespace cc { |
| |
| IOSurfaceLayerImpl::IOSurfaceLayerImpl(LayerTreeImpl* tree_impl, int id) |
| : LayerImpl(tree_impl, id), |
| io_surface_id_(0), |
| io_surface_changed_(false), |
| io_surface_texture_id_(0), |
| io_surface_resource_id_(0) {} |
| |
| IOSurfaceLayerImpl::~IOSurfaceLayerImpl() { |
| if (!io_surface_texture_id_) |
| return; |
| |
| DestroyTexture(); |
| } |
| |
| void IOSurfaceLayerImpl::DestroyTexture() { |
| if (io_surface_resource_id_) { |
| ResourceProvider* resource_provider = |
| layer_tree_impl()->resource_provider(); |
| resource_provider->DeleteResource(io_surface_resource_id_); |
| io_surface_resource_id_ = 0; |
| } |
| |
| if (io_surface_texture_id_) { |
| ContextProvider* context_provider = |
| layer_tree_impl()->output_surface()->context_provider().get(); |
| // TODO(skaslev): Implement this path for software compositing. |
| if (context_provider) |
| context_provider->Context3d()->deleteTexture(io_surface_texture_id_); |
| io_surface_texture_id_ = 0; |
| } |
| } |
| |
| scoped_ptr<LayerImpl> IOSurfaceLayerImpl::CreateLayerImpl( |
| LayerTreeImpl* tree_impl) { |
| return IOSurfaceLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); |
| } |
| |
| void IOSurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) { |
| LayerImpl::PushPropertiesTo(layer); |
| |
| IOSurfaceLayerImpl* io_surface_layer = |
| static_cast<IOSurfaceLayerImpl*>(layer); |
| io_surface_layer->SetIOSurfaceProperties(io_surface_id_, io_surface_size_); |
| } |
| |
| bool IOSurfaceLayerImpl::WillDraw(DrawMode draw_mode, |
| ResourceProvider* resource_provider) { |
| if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE) |
| return false; |
| |
| if (io_surface_changed_) { |
| ContextProvider* context_provider = |
| layer_tree_impl()->output_surface()->context_provider().get(); |
| if (!context_provider) { |
| // TODO(skaslev): Implement this path for software compositing. |
| return false; |
| } |
| |
| blink::WebGraphicsContext3D* context3d = context_provider->Context3d(); |
| |
| // TODO(ernstm): Do this in a way that we can track memory usage. |
| if (!io_surface_texture_id_) { |
| io_surface_texture_id_ = context3d->createTexture(); |
| io_surface_resource_id_ = |
| resource_provider->CreateResourceFromExternalTexture( |
| GL_TEXTURE_RECTANGLE_ARB, |
| io_surface_texture_id_); |
| } |
| |
| GLC(context3d, |
| context3d->bindTexture(GL_TEXTURE_RECTANGLE_ARB, |
| io_surface_texture_id_)); |
| context3d->texImageIOSurface2DCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, |
| io_surface_size_.width(), |
| io_surface_size_.height(), |
| io_surface_id_, |
| 0); |
| // Do not check for error conditions. texImageIOSurface2DCHROMIUM() is |
| // supposed to hold on to the last good IOSurface if the new one is already |
| // closed. This is only a possibility during live resizing of plugins. |
| // However, it seems that this is not sufficient to completely guard against |
| // garbage being drawn. If this is found to be a significant issue, it may |
| // be necessary to explicitly tell the embedder when to free the surfaces it |
| // has allocated. |
| io_surface_changed_ = false; |
| } |
| |
| return LayerImpl::WillDraw(draw_mode, resource_provider); |
| } |
| |
| void IOSurfaceLayerImpl::AppendQuads(QuadSink* quad_sink, |
| AppendQuadsData* append_quads_data) { |
| SharedQuadState* shared_quad_state = |
| quad_sink->UseSharedQuadState(CreateSharedQuadState()); |
| AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); |
| |
| gfx::Rect quad_rect(content_bounds()); |
| gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect()); |
| scoped_ptr<IOSurfaceDrawQuad> quad = IOSurfaceDrawQuad::Create(); |
| quad->SetNew(shared_quad_state, |
| quad_rect, |
| opaque_rect, |
| io_surface_size_, |
| io_surface_resource_id_, |
| IOSurfaceDrawQuad::FLIPPED); |
| quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data); |
| } |
| |
| void IOSurfaceLayerImpl::DidLoseOutputSurface() { |
| // We don't have a valid texture ID in the new context; however, |
| // the IOSurface is still valid. |
| DestroyTexture(); |
| io_surface_changed_ = true; |
| } |
| |
| void IOSurfaceLayerImpl::SetIOSurfaceProperties(unsigned io_surface_id, |
| gfx::Size size) { |
| if (io_surface_id_ != io_surface_id) |
| io_surface_changed_ = true; |
| |
| io_surface_id_ = io_surface_id; |
| io_surface_size_ = size; |
| } |
| |
| const char* IOSurfaceLayerImpl::LayerTypeAsString() const { |
| return "cc::IOSurfaceLayerImpl"; |
| } |
| |
| } // namespace cc |