Home | History | Annotate | Download | only in gpu
      1 // Copyright (c) 2013 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/stream_texture_android.h"
      6 
      7 #include "base/bind.h"
      8 #include "content/common/android/surface_texture_peer.h"
      9 #include "content/common/gpu/gpu_channel.h"
     10 #include "content/common/gpu/gpu_messages.h"
     11 #include "gpu/command_buffer/service/context_group.h"
     12 #include "gpu/command_buffer/service/context_state.h"
     13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
     14 #include "gpu/command_buffer/service/texture_manager.h"
     15 #include "ui/gfx/size.h"
     16 #include "ui/gl/scoped_make_current.h"
     17 
     18 namespace content {
     19 
     20 using gpu::gles2::ContextGroup;
     21 using gpu::gles2::GLES2Decoder;
     22 using gpu::gles2::TextureManager;
     23 using gpu::gles2::TextureRef;
     24 
     25 // static
     26 bool StreamTexture::Create(
     27     GpuCommandBufferStub* owner_stub,
     28     uint32 client_texture_id,
     29     int stream_id) {
     30   GLES2Decoder* decoder = owner_stub->decoder();
     31   TextureManager* texture_manager =
     32       decoder->GetContextGroup()->texture_manager();
     33   TextureRef* texture = texture_manager->GetTexture(client_texture_id);
     34 
     35   if (texture && (!texture->texture()->target() ||
     36                   texture->texture()->target() == GL_TEXTURE_EXTERNAL_OES)) {
     37 
     38     // TODO: Ideally a valid image id was returned to the client so that
     39     // it could then call glBindTexImage2D() for doing the following.
     40     scoped_refptr<gfx::GLImage> gl_image(
     41         new StreamTexture(owner_stub, stream_id, texture->service_id()));
     42     gfx::Size size = gl_image->GetSize();
     43     texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES);
     44     texture_manager->SetLevelInfo(texture,
     45                                   GL_TEXTURE_EXTERNAL_OES,
     46                                   0,
     47                                   GL_RGBA,
     48                                   size.width(),
     49                                   size.height(),
     50                                   1,
     51                                   0,
     52                                   GL_RGBA,
     53                                   GL_UNSIGNED_BYTE,
     54                                   true);
     55     texture_manager->SetLevelImage(
     56         texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image);
     57     return true;
     58   }
     59 
     60   return false;
     61 }
     62 
     63 StreamTexture::StreamTexture(GpuCommandBufferStub* owner_stub,
     64                              int32 route_id,
     65                              uint32 texture_id)
     66     : surface_texture_(gfx::SurfaceTexture::Create(texture_id)),
     67       size_(0, 0),
     68       has_valid_frame_(false),
     69       has_pending_frame_(false),
     70       owner_stub_(owner_stub),
     71       route_id_(route_id),
     72       has_listener_(false),
     73       weak_factory_(this) {
     74   owner_stub->AddDestructionObserver(this);
     75   memset(current_matrix_, 0, sizeof(current_matrix_));
     76   owner_stub->channel()->AddRoute(route_id, this);
     77   surface_texture_->SetFrameAvailableCallback(base::Bind(
     78       &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr()));
     79 }
     80 
     81 StreamTexture::~StreamTexture() {
     82   if (owner_stub_) {
     83     owner_stub_->RemoveDestructionObserver(this);
     84     owner_stub_->channel()->RemoveRoute(route_id_);
     85   }
     86 }
     87 
     88 void StreamTexture::OnWillDestroyStub() {
     89   owner_stub_->RemoveDestructionObserver(this);
     90   owner_stub_->channel()->RemoveRoute(route_id_);
     91   owner_stub_ = NULL;
     92 
     93   // If the owner goes away, there is no need to keep the SurfaceTexture around.
     94   // The GL texture will keep working regardless with the currently bound frame.
     95   surface_texture_ = NULL;
     96 }
     97 
     98 void StreamTexture::Destroy() {
     99   NOTREACHED();
    100 }
    101 
    102 void StreamTexture::WillUseTexImage() {
    103   if (!owner_stub_ || !surface_texture_.get())
    104     return;
    105 
    106   if (has_pending_frame_) {
    107     scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
    108     bool needs_make_current =
    109         !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL);
    110     // On Android we should not have to perform a real context switch here when
    111     // using virtual contexts.
    112     DCHECK(!needs_make_current || !owner_stub_->decoder()
    113                                        ->GetContextGroup()
    114                                        ->feature_info()
    115                                        ->workarounds()
    116                                        .use_virtualized_gl_contexts);
    117     if (needs_make_current) {
    118       scoped_make_current.reset(new ui::ScopedMakeCurrent(
    119           owner_stub_->decoder()->GetGLContext(), owner_stub_->surface()));
    120     }
    121     surface_texture_->UpdateTexImage();
    122     has_valid_frame_ = true;
    123     has_pending_frame_ = false;
    124     if (scoped_make_current.get()) {
    125       // UpdateTexImage() implies glBindTexture().
    126       // The cmd decoder takes care of restoring the binding for this GLImage as
    127       // far as the current context is concerned, but if we temporarily change
    128       // it, we have to keep the state intact in *that* context also.
    129       const gpu::gles2::ContextState* state =
    130           owner_stub_->decoder()->GetContextState();
    131       const gpu::gles2::TextureUnit& active_unit =
    132           state->texture_units[state->active_texture_unit];
    133       glBindTexture(GL_TEXTURE_EXTERNAL_OES,
    134                     active_unit.bound_texture_external_oes
    135                         ? active_unit.bound_texture_external_oes->service_id()
    136                         : 0);
    137     }
    138   }
    139 
    140   if (has_listener_ && has_valid_frame_) {
    141     float mtx[16];
    142     surface_texture_->GetTransformMatrix(mtx);
    143 
    144     // Only query the matrix once we have bound a valid frame.
    145     if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) {
    146       memcpy(current_matrix_, mtx, sizeof(mtx));
    147 
    148       GpuStreamTextureMsg_MatrixChanged_Params params;
    149       memcpy(&params.m00, mtx, sizeof(mtx));
    150       owner_stub_->channel()->Send(
    151           new GpuStreamTextureMsg_MatrixChanged(route_id_, params));
    152     }
    153   }
    154 }
    155 
    156 void StreamTexture::OnFrameAvailable() {
    157   has_pending_frame_ = true;
    158   if (has_listener_ && owner_stub_) {
    159     owner_stub_->channel()->Send(
    160         new GpuStreamTextureMsg_FrameAvailable(route_id_));
    161   }
    162 }
    163 
    164 gfx::Size StreamTexture::GetSize() {
    165   return size_;
    166 }
    167 
    168 bool StreamTexture::OnMessageReceived(const IPC::Message& message) {
    169   bool handled = true;
    170   IPC_BEGIN_MESSAGE_MAP(StreamTexture, message)
    171     IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_StartListening, OnStartListening)
    172     IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_EstablishPeer, OnEstablishPeer)
    173     IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_SetSize, OnSetSize)
    174     IPC_MESSAGE_UNHANDLED(handled = false)
    175   IPC_END_MESSAGE_MAP()
    176 
    177   DCHECK(handled);
    178   return handled;
    179 }
    180 
    181 void StreamTexture::OnStartListening() {
    182   DCHECK(!has_listener_);
    183   has_listener_ = true;
    184 }
    185 
    186 void StreamTexture::OnEstablishPeer(int32 primary_id, int32 secondary_id) {
    187   if (!owner_stub_)
    188     return;
    189 
    190   base::ProcessHandle process = owner_stub_->channel()->renderer_pid();
    191 
    192   SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer(
    193       process, surface_texture_, primary_id, secondary_id);
    194 }
    195 
    196 bool StreamTexture::BindTexImage(unsigned target) {
    197   NOTREACHED();
    198   return false;
    199 }
    200 
    201 void StreamTexture::ReleaseTexImage(unsigned target) {
    202   NOTREACHED();
    203 }
    204 
    205 }  // namespace content
    206