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/stream_texture_manager_android.h"
6
7#include "base/bind.h"
8#include "content/common/gpu/gpu_channel.h"
9#include "content/common/gpu/gpu_messages.h"
10#include "gpu/command_buffer/service/stream_texture.h"
11#include "ui/gfx/size.h"
12#include "ui/gl/android/surface_texture_bridge.h"
13#include "ui/gl/gl_bindings.h"
14
15namespace content {
16
17StreamTextureManagerAndroid::StreamTextureAndroid::StreamTextureAndroid(
18    GpuChannel* channel, int service_id)
19    : surface_texture_bridge_(new gfx::SurfaceTextureBridge(service_id)),
20      size_(0, 0),
21      has_updated_(false),
22      channel_(channel) {
23  memset(current_matrix_, 0, sizeof(current_matrix_));
24}
25
26StreamTextureManagerAndroid::StreamTextureAndroid::~StreamTextureAndroid() {
27}
28
29void StreamTextureManagerAndroid::StreamTextureAndroid::Update() {
30  GLint texture_id = 0;
31  glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id);
32  surface_texture_bridge_->UpdateTexImage();
33  glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
34  if (matrix_callback_.is_null())
35    return;
36
37  float mtx[16];
38  surface_texture_bridge_->GetTransformMatrix(mtx);
39
40  // Only query the matrix once we have bound a valid frame.
41  if (has_updated_ && memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) {
42    memcpy(current_matrix_, mtx, sizeof(mtx));
43
44    GpuStreamTextureMsg_MatrixChanged_Params params;
45    memcpy(&params.m00, mtx, sizeof(mtx));
46    matrix_callback_.Run(params);
47  }
48}
49
50void StreamTextureManagerAndroid::StreamTextureAndroid::OnFrameAvailable(
51    int route_id) {
52  has_updated_ = true;
53  channel_->Send(new GpuStreamTextureMsg_FrameAvailable(route_id));
54}
55
56gfx::Size StreamTextureManagerAndroid::StreamTextureAndroid::GetSize() {
57  return size_;
58}
59
60StreamTextureManagerAndroid::StreamTextureManagerAndroid(
61    GpuChannel* channel)
62    : channel_(channel) {
63}
64
65StreamTextureManagerAndroid::~StreamTextureManagerAndroid() {
66  DCHECK(textures_.size() == textures_from_service_id_.size());
67  if (!textures_.IsEmpty())
68    LOG(WARNING) << "Undestroyed surface textures while closing GPU channel.";
69}
70
71GLuint StreamTextureManagerAndroid::CreateStreamTexture(uint32 service_id,
72                                                        uint32 client_id) {
73  // service_id: the actual GL texture name
74  // client_id: texture name given to the client in the renderer (unused here)
75  // The return value here is what glCreateStreamTextureCHROMIUM() will return
76  // to identify the stream (i.e. surface texture).
77  StreamTextureAndroid* texture = new StreamTextureAndroid(
78      channel_, service_id);
79  textures_from_service_id_.AddWithID(texture, service_id);
80  return textures_.Add(texture);
81}
82
83void StreamTextureManagerAndroid::DestroyStreamTexture(uint32 service_id) {
84  gpu::StreamTexture* texture = textures_from_service_id_.Lookup(service_id);
85  if (texture) {
86    textures_from_service_id_.Remove(service_id);
87
88    for (TextureMap::Iterator<StreamTextureAndroid> it(&textures_);
89        !it.IsAtEnd(); it.Advance()) {
90      if (it.GetCurrentValue() == texture) {
91        textures_.Remove(it.GetCurrentKey());
92        break;
93      }
94    }
95  }
96}
97
98gpu::StreamTexture* StreamTextureManagerAndroid::LookupStreamTexture(
99    uint32 service_id) {
100  return textures_from_service_id_.Lookup(service_id);
101}
102
103void StreamTextureManagerAndroid::SendMatrixChanged(
104    int route_id,
105    const GpuStreamTextureMsg_MatrixChanged_Params& params) {
106  channel_->Send(new GpuStreamTextureMsg_MatrixChanged(route_id, params));
107}
108
109void StreamTextureManagerAndroid::RegisterStreamTextureProxy(
110    int32 stream_id, int32 route_id) {
111  StreamTextureAndroid* stream_texture = textures_.Lookup(stream_id);
112  if (stream_texture) {
113    // TODO(sievers): Post from binder thread to IO thread directly.
114    base::Closure frame_cb = base::Bind(
115          &StreamTextureAndroid::OnFrameAvailable,
116          stream_texture->AsWeakPtr(),
117          route_id);
118    StreamTextureAndroid::MatrixChangedCB matrix_cb = base::Bind(
119          &StreamTextureManagerAndroid::SendMatrixChanged,
120          base::Unretained(this),
121          route_id);
122    stream_texture->set_matrix_changed_callback(matrix_cb);
123    stream_texture->surface_texture_bridge()->SetFrameAvailableCallback(
124        frame_cb);
125  }
126}
127
128void StreamTextureManagerAndroid::EstablishStreamTexture(
129    int32 stream_id, int32 primary_id, int32 secondary_id) {
130  StreamTextureAndroid* stream_texture = textures_.Lookup(stream_id);
131  base::ProcessHandle process = channel_->renderer_pid();
132
133  if (stream_texture) {
134    SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer(
135        process,
136        stream_texture->surface_texture_bridge(),
137        primary_id,
138        secondary_id);
139  }
140}
141
142void StreamTextureManagerAndroid::SetStreamTextureSize(
143    int32 stream_id, const gfx::Size& size) {
144  StreamTextureAndroid* stream_texture = textures_.Lookup(stream_id);
145  if (stream_texture)
146    stream_texture->SetSize(size);
147}
148
149}  // namespace content
150