Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2012 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 "content/common/gpu/image_transport_surface.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/compiler_specific.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "base/win/windows_version.h"
     13 #include "content/common/gpu/gpu_messages.h"
     14 #include "content/public/common/content_switches.h"
     15 #include "ui/gfx/native_widget_types.h"
     16 #include "ui/gl/gl_bindings.h"
     17 #include "ui/gl/gl_context.h"
     18 #include "ui/gl/gl_implementation.h"
     19 #include "ui/gl/gl_surface_egl.h"
     20 
     21 namespace content {
     22 namespace {
     23 
     24 // We are backed by an Pbuffer offscreen surface through which ANGLE provides
     25 // a handle to the corresponding render target texture through an extension.
     26 class PbufferImageTransportSurface
     27     : public gfx::GLSurfaceAdapter,
     28       public ImageTransportSurface,
     29       public base::SupportsWeakPtr<PbufferImageTransportSurface> {
     30  public:
     31   PbufferImageTransportSurface(GpuChannelManager* manager,
     32                                GpuCommandBufferStub* stub);
     33 
     34   // gfx::GLSurface implementation
     35   virtual bool Initialize() OVERRIDE;
     36   virtual void Destroy() OVERRIDE;
     37   virtual bool DeferDraws() OVERRIDE;
     38   virtual bool IsOffscreen() OVERRIDE;
     39   virtual bool SwapBuffers() OVERRIDE;
     40   virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
     41   virtual std::string GetExtensions() OVERRIDE;
     42   virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE;
     43   virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE;
     44 
     45  protected:
     46   // ImageTransportSurface implementation
     47   virtual void OnBufferPresented(
     48       const AcceleratedSurfaceMsg_BufferPresented_Params& params) OVERRIDE;
     49   virtual void OnResizeViewACK() OVERRIDE;
     50   virtual void OnResize(gfx::Size size, float scale_factor) OVERRIDE;
     51   virtual void SetLatencyInfo(const ui::LatencyInfo&) OVERRIDE;
     52   virtual gfx::Size GetSize() OVERRIDE;
     53 
     54  private:
     55   virtual ~PbufferImageTransportSurface();
     56   void SendBuffersSwapped();
     57   void DestroySurface();
     58 
     59   // Tracks the current buffer allocation state.
     60   bool backbuffer_suggested_allocation_;
     61   bool frontbuffer_suggested_allocation_;
     62 
     63   // Whether a SwapBuffers is pending.
     64   bool is_swap_buffers_pending_;
     65 
     66   // Whether we unscheduled command buffer because of pending SwapBuffers.
     67   bool did_unschedule_;
     68 
     69   // Size to resize to when the surface becomes visible.
     70   gfx::Size visible_size_;
     71 
     72   ui::LatencyInfo latency_info_;
     73 
     74   scoped_ptr<ImageTransportHelper> helper_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(PbufferImageTransportSurface);
     77 };
     78 
     79 PbufferImageTransportSurface::PbufferImageTransportSurface(
     80     GpuChannelManager* manager,
     81     GpuCommandBufferStub* stub)
     82     : GLSurfaceAdapter(new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1))),
     83       backbuffer_suggested_allocation_(true),
     84       frontbuffer_suggested_allocation_(true),
     85       is_swap_buffers_pending_(false),
     86       did_unschedule_(false) {
     87   helper_.reset(new ImageTransportHelper(this,
     88                                          manager,
     89                                          stub,
     90                                          gfx::kNullPluginWindow));
     91 }
     92 
     93 PbufferImageTransportSurface::~PbufferImageTransportSurface() {
     94   Destroy();
     95 }
     96 
     97 bool PbufferImageTransportSurface::Initialize() {
     98   // Only support this path if the GL implementation is ANGLE.
     99   // IO surfaces will not work with, for example, OSMesa software renderer
    100   // GL contexts.
    101   if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2)
    102     return false;
    103 
    104   if (!helper_->Initialize())
    105     return false;
    106 
    107   return GLSurfaceAdapter::Initialize();
    108 }
    109 
    110 void PbufferImageTransportSurface::Destroy() {
    111   helper_->Destroy();
    112   GLSurfaceAdapter::Destroy();
    113 }
    114 
    115 bool PbufferImageTransportSurface::DeferDraws() {
    116   // The command buffer hit a draw/clear command that could clobber the
    117   // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort
    118   // processing of the command by returning true and unschedule until the Swap
    119   // Ack arrives.
    120   if (did_unschedule_)
    121     return true;
    122   if (is_swap_buffers_pending_) {
    123     did_unschedule_ = true;
    124     helper_->SetScheduled(false);
    125     return true;
    126   }
    127   return false;
    128 }
    129 
    130 bool PbufferImageTransportSurface::IsOffscreen() {
    131   return false;
    132 }
    133 
    134 bool PbufferImageTransportSurface::SwapBuffers() {
    135   DCHECK(backbuffer_suggested_allocation_);
    136   if (!frontbuffer_suggested_allocation_)
    137     return true;
    138 
    139   HANDLE surface_handle = GetShareHandle();
    140   if (!surface_handle)
    141     return false;
    142 
    143   // Don't send the surface to the browser until we hit the fence that
    144   // indicates the drawing to the surface has been completed.
    145   // TODO(jbates) unscheduling should be deferred until draw commands from the
    146   // next frame -- otherwise the GPU is potentially sitting idle.
    147   helper_->DeferToFence(base::Bind(
    148       &PbufferImageTransportSurface::SendBuffersSwapped,
    149       AsWeakPtr()));
    150 
    151   return true;
    152 }
    153 
    154 bool PbufferImageTransportSurface::PostSubBuffer(
    155     int x, int y, int width, int height) {
    156   NOTREACHED();
    157   return false;
    158 }
    159 
    160 bool PbufferImageTransportSurface::SetBackbufferAllocation(bool allocation) {
    161   if (backbuffer_suggested_allocation_ == allocation)
    162     return true;
    163   backbuffer_suggested_allocation_ = allocation;
    164 
    165   DestroySurface();
    166 
    167   if (backbuffer_suggested_allocation_ && visible_size_.GetArea() != 0)
    168     return Resize(visible_size_);
    169   else
    170     return Resize(gfx::Size(1, 1));
    171 }
    172 
    173 void PbufferImageTransportSurface::SetFrontbufferAllocation(bool allocation) {
    174   if (frontbuffer_suggested_allocation_ == allocation)
    175     return;
    176   frontbuffer_suggested_allocation_ = allocation;
    177 
    178   // We recreate frontbuffer by recreating backbuffer and swapping.
    179   // But we release frontbuffer by telling UI to release its handle on it.
    180   if (!frontbuffer_suggested_allocation_)
    181     helper_->Suspend();
    182 }
    183 
    184 void PbufferImageTransportSurface::DestroySurface() {
    185   GpuHostMsg_AcceleratedSurfaceRelease_Params params;
    186   helper_->SendAcceleratedSurfaceRelease(params);
    187 }
    188 
    189 std::string PbufferImageTransportSurface::GetExtensions() {
    190   std::string extensions = gfx::GLSurface::GetExtensions();
    191   extensions += extensions.empty() ? "" : " ";
    192   extensions += "GL_CHROMIUM_front_buffer_cached";
    193   return extensions;
    194 }
    195 
    196 void PbufferImageTransportSurface::SendBuffersSwapped() {
    197   GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
    198   params.surface_handle = reinterpret_cast<int64>(GetShareHandle());
    199   CHECK(params.surface_handle);
    200   params.size = GetSize();
    201   params.latency_info = latency_info_;
    202 
    203   helper_->SendAcceleratedSurfaceBuffersSwapped(params);
    204 
    205   DCHECK(!is_swap_buffers_pending_);
    206   is_swap_buffers_pending_ = true;
    207 }
    208 
    209 void PbufferImageTransportSurface::OnBufferPresented(
    210     const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) {
    211   is_swap_buffers_pending_ = false;
    212   if (did_unschedule_) {
    213     did_unschedule_ = false;
    214     helper_->SetScheduled(true);
    215   }
    216 }
    217 
    218 void PbufferImageTransportSurface::OnResizeViewACK() {
    219   NOTREACHED();
    220 }
    221 
    222 void PbufferImageTransportSurface::OnResize(gfx::Size size,
    223                                             float scale_factor) {
    224   DCHECK(backbuffer_suggested_allocation_);
    225   DCHECK(frontbuffer_suggested_allocation_);
    226   Resize(size);
    227 
    228   DestroySurface();
    229 
    230   visible_size_ = size;
    231 }
    232 
    233 void PbufferImageTransportSurface::SetLatencyInfo(
    234     const ui::LatencyInfo& latency_info) {
    235   latency_info_ = latency_info;
    236 }
    237 
    238 gfx::Size PbufferImageTransportSurface::GetSize() {
    239   return GLSurfaceAdapter::GetSize();
    240 }
    241 
    242 }  // namespace anonymous
    243 
    244 // static
    245 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
    246     GpuChannelManager* manager,
    247     GpuCommandBufferStub* stub,
    248     const gfx::GLSurfaceHandle& handle) {
    249   DCHECK(handle.handle);
    250   DCHECK(handle.transport_type == gfx::NATIVE_DIRECT ||
    251          handle.transport_type == gfx::NATIVE_TRANSPORT);
    252   if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
    253       !CommandLine::ForCurrentProcess()->HasSwitch(
    254           switches::kDisableImageTransportSurface)) {
    255     // This path handles two different cases.
    256     //
    257     // For post-Vista regular Windows, this surface will be used for
    258     // renderer compositors.
    259     //
    260     // For Aura Windows, this will be the surface for the browser compositor
    261     // (and the renderer compositors surface's will be
    262     // TextureImageTransportSurface above).
    263     const char* extensions = eglQueryString(
    264         gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_EXTENSIONS);
    265     if (extensions &&
    266         strstr(extensions, "EGL_ANGLE_query_surface_pointer") &&
    267         strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) {
    268       return scoped_refptr<gfx::GLSurface>(
    269           new PbufferImageTransportSurface(manager, stub));
    270     }
    271   }
    272 
    273   scoped_refptr<gfx::GLSurface> surface =
    274       gfx::GLSurface::CreateViewGLSurface(handle.handle);
    275   if (!surface)
    276     return surface;
    277   return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
    278       manager, stub, surface.get(), handle.is_transport()));
    279 }
    280 
    281 }  // namespace content
    282