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/renderer/gpu/mailbox_output_surface.h"
      6 
      7 #include "base/logging.h"
      8 #include "cc/output/compositor_frame.h"
      9 #include "cc/output/compositor_frame_ack.h"
     10 #include "cc/output/gl_frame_data.h"
     11 #include "cc/resources/resource_provider.h"
     12 #include "gpu/command_buffer/client/gles2_interface.h"
     13 #include "third_party/khronos/GLES2/gl2.h"
     14 #include "third_party/khronos/GLES2/gl2ext.h"
     15 
     16 using cc::CompositorFrame;
     17 using cc::GLFrameData;
     18 using cc::ResourceProvider;
     19 using gpu::Mailbox;
     20 using gpu::gles2::GLES2Interface;
     21 
     22 namespace content {
     23 
     24 MailboxOutputSurface::MailboxOutputSurface(
     25     int32 routing_id,
     26     uint32 output_surface_id,
     27     const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
     28     scoped_ptr<cc::SoftwareOutputDevice> software_device,
     29     cc::ResourceFormat format)
     30     : CompositorOutputSurface(routing_id,
     31                               output_surface_id,
     32                               context_provider,
     33                               software_device.Pass(),
     34                               true),
     35       fbo_(0),
     36       is_backbuffer_discarded_(false),
     37       format_(format) {
     38   pending_textures_.push_back(TransferableFrame());
     39   capabilities_.max_frames_pending = 1;
     40   capabilities_.uses_default_gl_framebuffer = false;
     41 }
     42 
     43 MailboxOutputSurface::~MailboxOutputSurface() {
     44   DiscardBackbuffer();
     45   while (!pending_textures_.empty()) {
     46     if (pending_textures_.front().texture_id) {
     47       context_provider_->ContextGL()->DeleteTextures(
     48           1, &pending_textures_.front().texture_id);
     49     }
     50     pending_textures_.pop_front();
     51   }
     52 }
     53 
     54 void MailboxOutputSurface::EnsureBackbuffer() {
     55   is_backbuffer_discarded_ = false;
     56 
     57   GLES2Interface* gl = context_provider_->ContextGL();
     58 
     59   if (!current_backing_.texture_id) {
     60     // Find a texture of matching size to recycle.
     61     while (!returned_textures_.empty()) {
     62       TransferableFrame& texture = returned_textures_.front();
     63       if (texture.size == surface_size_) {
     64         current_backing_ = texture;
     65         if (current_backing_.sync_point)
     66           gl->WaitSyncPointCHROMIUM(current_backing_.sync_point);
     67         returned_textures_.pop();
     68         break;
     69       }
     70 
     71       gl->DeleteTextures(1, &texture.texture_id);
     72       returned_textures_.pop();
     73     }
     74 
     75     if (!current_backing_.texture_id) {
     76       gl->GenTextures(1, &current_backing_.texture_id);
     77       current_backing_.size = surface_size_;
     78       gl->BindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
     79       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     80       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     81       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
     82       gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     83       gl->TexImage2D(GL_TEXTURE_2D,
     84                      0,
     85                      GLInternalFormat(format_),
     86                      surface_size_.width(),
     87                      surface_size_.height(),
     88                      0,
     89                      GLDataFormat(format_),
     90                      GLDataType(format_),
     91                      NULL);
     92       gl->GenMailboxCHROMIUM(current_backing_.mailbox.name);
     93       gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, current_backing_.mailbox.name);
     94     }
     95   }
     96 }
     97 
     98 void MailboxOutputSurface::DiscardBackbuffer() {
     99   is_backbuffer_discarded_ = true;
    100 
    101   GLES2Interface* gl = context_provider_->ContextGL();
    102 
    103   if (current_backing_.texture_id) {
    104     gl->DeleteTextures(1, &current_backing_.texture_id);
    105     current_backing_ = TransferableFrame();
    106   }
    107 
    108   while (!returned_textures_.empty()) {
    109     const TransferableFrame& frame = returned_textures_.front();
    110     gl->DeleteTextures(1, &frame.texture_id);
    111     returned_textures_.pop();
    112   }
    113 
    114   if (fbo_) {
    115     gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
    116     gl->DeleteFramebuffers(1, &fbo_);
    117     fbo_ = 0;
    118   }
    119 }
    120 
    121 void MailboxOutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
    122   if (size == surface_size_)
    123     return;
    124 
    125   surface_size_ = size;
    126   device_scale_factor_ = scale_factor;
    127   DiscardBackbuffer();
    128   EnsureBackbuffer();
    129 }
    130 
    131 void MailboxOutputSurface::BindFramebuffer() {
    132   EnsureBackbuffer();
    133   DCHECK(current_backing_.texture_id);
    134 
    135   GLES2Interface* gl = context_provider_->ContextGL();
    136 
    137   if (!fbo_)
    138     gl->GenFramebuffers(1, &fbo_);
    139   gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
    140   gl->FramebufferTexture2D(GL_FRAMEBUFFER,
    141                            GL_COLOR_ATTACHMENT0,
    142                            GL_TEXTURE_2D,
    143                            current_backing_.texture_id,
    144                            0);
    145 }
    146 
    147 void MailboxOutputSurface::OnSwapAck(uint32 output_surface_id,
    148                                      const cc::CompositorFrameAck& ack) {
    149   // Ignore message if it's a stale one coming from a different output surface
    150   // (e.g. after a lost context).
    151   if (output_surface_id != output_surface_id_) {
    152     CompositorOutputSurface::OnSwapAck(output_surface_id, ack);
    153     return;
    154   }
    155   if (!ack.gl_frame_data->mailbox.IsZero()) {
    156     DCHECK(!ack.gl_frame_data->size.IsEmpty());
    157     // The browser could be returning the oldest or any other pending texture
    158     // if it decided to skip a frame.
    159     std::deque<TransferableFrame>::iterator it;
    160     for (it = pending_textures_.begin(); it != pending_textures_.end(); it++) {
    161       DCHECK(!it->mailbox.IsZero());
    162       if (!memcmp(it->mailbox.name,
    163                   ack.gl_frame_data->mailbox.name,
    164                   sizeof(it->mailbox.name))) {
    165         DCHECK(it->size == ack.gl_frame_data->size);
    166         break;
    167       }
    168     }
    169     DCHECK(it != pending_textures_.end());
    170     it->sync_point = ack.gl_frame_data->sync_point;
    171 
    172     if (!is_backbuffer_discarded_) {
    173       returned_textures_.push(*it);
    174     } else {
    175       context_provider_->ContextGL()->DeleteTextures(1, &it->texture_id);
    176     }
    177 
    178     pending_textures_.erase(it);
    179   } else {
    180     DCHECK(!pending_textures_.empty());
    181     // The browser always keeps one texture as the frontbuffer.
    182     // If it does not return a mailbox, it discarded the frontbuffer which is
    183     // the oldest texture we sent.
    184     uint32 texture_id = pending_textures_.front().texture_id;
    185     if (texture_id)
    186       context_provider_->ContextGL()->DeleteTextures(1, &texture_id);
    187     pending_textures_.pop_front();
    188   }
    189   CompositorOutputSurface::OnSwapAck(output_surface_id, ack);
    190 }
    191 
    192 void MailboxOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
    193   DCHECK(frame->gl_frame_data);
    194   DCHECK(!surface_size_.IsEmpty());
    195   DCHECK(surface_size_ == current_backing_.size);
    196   DCHECK(frame->gl_frame_data->size == current_backing_.size);
    197   DCHECK(!current_backing_.mailbox.IsZero() ||
    198          context_provider_->IsContextLost());
    199 
    200   frame->gl_frame_data->mailbox = current_backing_.mailbox;
    201   context_provider_->ContextGL()->Flush();
    202   frame->gl_frame_data->sync_point =
    203       context_provider_->ContextGL()->InsertSyncPointCHROMIUM();
    204   CompositorOutputSurface::SwapBuffers(frame);
    205 
    206   pending_textures_.push_back(current_backing_);
    207   current_backing_ = TransferableFrame();
    208 }
    209 
    210 size_t MailboxOutputSurface::GetNumAcksPending() {
    211   DCHECK(pending_textures_.size());
    212   return pending_textures_.size() - 1;
    213 }
    214 
    215 }  // namespace content
    216