OLD | NEW |
| (Empty) |
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 <string.h> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/strings/stringize_macros.h" | |
11 #include "content/common/gpu/gpu_channel.h" | |
12 #include "gpu/command_buffer/service/context_group.h" | |
13 #include "gpu/command_buffer/service/context_state.h" | |
14 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" | |
15 #include "gpu/command_buffer/service/texture_manager.h" | |
16 #include "gpu/ipc/common/android/surface_texture_peer.h" | |
17 #include "gpu/ipc/common/gpu_messages.h" | |
18 #include "ui/gfx/geometry/size.h" | |
19 #include "ui/gl/gl_context.h" | |
20 #include "ui/gl/gl_helper.h" | |
21 #include "ui/gl/scoped_binders.h" | |
22 #include "ui/gl/scoped_make_current.h" | |
23 | |
24 namespace content { | |
25 | |
26 using gpu::gles2::ContextGroup; | |
27 using gpu::gles2::GLES2Decoder; | |
28 using gpu::gles2::TextureManager; | |
29 using gpu::gles2::TextureRef; | |
30 | |
31 // static | |
32 bool StreamTexture::Create(GpuCommandBufferStub* owner_stub, | |
33 uint32_t client_texture_id, | |
34 int stream_id) { | |
35 GLES2Decoder* decoder = owner_stub->decoder(); | |
36 TextureManager* texture_manager = | |
37 decoder->GetContextGroup()->texture_manager(); | |
38 TextureRef* texture = texture_manager->GetTexture(client_texture_id); | |
39 | |
40 if (texture && (!texture->texture()->target() || | |
41 texture->texture()->target() == GL_TEXTURE_EXTERNAL_OES)) { | |
42 | |
43 // TODO: Ideally a valid image id was returned to the client so that | |
44 // it could then call glBindTexImage2D() for doing the following. | |
45 scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image( | |
46 new StreamTexture(owner_stub, stream_id, texture->service_id())); | |
47 gfx::Size size = gl_image->GetSize(); | |
48 texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES); | |
49 texture_manager->SetLevelInfo(texture, GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, | |
50 size.width(), size.height(), 1, 0, GL_RGBA, | |
51 GL_UNSIGNED_BYTE, gfx::Rect(size)); | |
52 texture_manager->SetLevelStreamTextureImage( | |
53 texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image.get(), | |
54 gpu::gles2::Texture::UNBOUND); | |
55 return true; | |
56 } | |
57 | |
58 return false; | |
59 } | |
60 | |
61 StreamTexture::StreamTexture(GpuCommandBufferStub* owner_stub, | |
62 int32_t route_id, | |
63 uint32_t texture_id) | |
64 : surface_texture_(gfx::SurfaceTexture::Create(texture_id)), | |
65 size_(0, 0), | |
66 has_pending_frame_(false), | |
67 owner_stub_(owner_stub), | |
68 route_id_(route_id), | |
69 has_listener_(false), | |
70 texture_id_(texture_id), | |
71 framebuffer_(0), | |
72 vertex_shader_(0), | |
73 fragment_shader_(0), | |
74 program_(0), | |
75 vertex_buffer_(0), | |
76 u_xform_location_(-1), | |
77 weak_factory_(this) { | |
78 owner_stub->AddDestructionObserver(this); | |
79 memset(current_matrix_, 0, sizeof(current_matrix_)); | |
80 owner_stub->channel()->AddRoute(route_id, owner_stub->stream_id(), this); | |
81 surface_texture_->SetFrameAvailableCallback(base::Bind( | |
82 &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr())); | |
83 } | |
84 | |
85 StreamTexture::~StreamTexture() { | |
86 if (owner_stub_) { | |
87 owner_stub_->RemoveDestructionObserver(this); | |
88 owner_stub_->channel()->RemoveRoute(route_id_); | |
89 } | |
90 } | |
91 | |
92 // gpu::gles2::GLStreamTextureMatrix implementation | |
93 void StreamTexture::GetTextureMatrix(float xform[16]) { | |
94 UpdateTexImage(); | |
95 surface_texture_->GetTransformMatrix(xform); | |
96 } | |
97 | |
98 void StreamTexture::OnWillDestroyStub() { | |
99 owner_stub_->RemoveDestructionObserver(this); | |
100 owner_stub_->channel()->RemoveRoute(route_id_); | |
101 | |
102 if (framebuffer_) { | |
103 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent()); | |
104 | |
105 glDeleteProgram(program_); | |
106 glDeleteShader(vertex_shader_); | |
107 glDeleteShader(fragment_shader_); | |
108 glDeleteBuffersARB(1, &vertex_buffer_); | |
109 glDeleteFramebuffersEXT(1, &framebuffer_); | |
110 program_ = 0; | |
111 vertex_shader_ = 0; | |
112 fragment_shader_ = 0; | |
113 vertex_buffer_ = 0; | |
114 framebuffer_ = 0; | |
115 u_xform_location_ = -1; | |
116 } | |
117 | |
118 owner_stub_ = NULL; | |
119 | |
120 // If the owner goes away, there is no need to keep the SurfaceTexture around. | |
121 // The GL texture will keep working regardless with the currently bound frame. | |
122 surface_texture_ = NULL; | |
123 } | |
124 | |
125 void StreamTexture::Destroy(bool have_context) { | |
126 NOTREACHED(); | |
127 } | |
128 | |
129 scoped_ptr<ui::ScopedMakeCurrent> StreamTexture::MakeStubCurrent() { | |
130 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; | |
131 bool needs_make_current = | |
132 !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL); | |
133 if (needs_make_current) { | |
134 scoped_make_current.reset(new ui::ScopedMakeCurrent( | |
135 owner_stub_->decoder()->GetGLContext(), owner_stub_->surface())); | |
136 } | |
137 return scoped_make_current; | |
138 } | |
139 | |
140 void StreamTexture::UpdateTexImage() { | |
141 DCHECK(surface_texture_.get()); | |
142 DCHECK(owner_stub_); | |
143 | |
144 if (!has_pending_frame_) return; | |
145 | |
146 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent()); | |
147 | |
148 surface_texture_->UpdateTexImage(); | |
149 | |
150 has_pending_frame_ = false; | |
151 | |
152 if (scoped_make_current.get()) { | |
153 // UpdateTexImage() implies glBindTexture(). | |
154 // The cmd decoder takes care of restoring the binding for this GLImage as | |
155 // far as the current context is concerned, but if we temporarily change | |
156 // it, we have to keep the state intact in *that* context also. | |
157 const gpu::gles2::ContextState* state = | |
158 owner_stub_->decoder()->GetContextState(); | |
159 const gpu::gles2::TextureUnit& active_unit = | |
160 state->texture_units[state->active_texture_unit]; | |
161 glBindTexture(GL_TEXTURE_EXTERNAL_OES, | |
162 active_unit.bound_texture_external_oes.get() | |
163 ? active_unit.bound_texture_external_oes->service_id() | |
164 : 0); | |
165 } | |
166 } | |
167 | |
168 bool StreamTexture::CopyTexImage(unsigned target) { | |
169 if (target != GL_TEXTURE_EXTERNAL_OES) | |
170 return false; | |
171 | |
172 if (!owner_stub_ || !surface_texture_.get()) | |
173 return true; | |
174 | |
175 GLint texture_id; | |
176 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id); | |
177 | |
178 // The following code only works if we're being asked to copy into | |
179 // |texture_id_|. Copying into a different texture is not supported. | |
180 // On some devices GL_TEXTURE_BINDING_EXTERNAL_OES is not supported as | |
181 // glGetIntegerv() parameter. In this case the value of |texture_id| will be | |
182 // zero and we assume that it is properly bound to |texture_id_|. | |
183 if (texture_id > 0 && static_cast<unsigned>(texture_id) != texture_id_) | |
184 return false; | |
185 | |
186 UpdateTexImage(); | |
187 | |
188 TextureManager* texture_manager = | |
189 owner_stub_->decoder()->GetContextGroup()->texture_manager(); | |
190 gpu::gles2::Texture* texture = | |
191 texture_manager->GetTextureForServiceId(texture_id_); | |
192 if (texture) { | |
193 // By setting image state to UNBOUND instead of COPIED we ensure that | |
194 // CopyTexImage() is called each time the surface texture is used for | |
195 // drawing. | |
196 texture->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this, | |
197 gpu::gles2::Texture::UNBOUND); | |
198 } | |
199 | |
200 return true; | |
201 } | |
202 | |
203 void StreamTexture::OnFrameAvailable() { | |
204 has_pending_frame_ = true; | |
205 if (has_listener_ && owner_stub_) { | |
206 owner_stub_->channel()->Send( | |
207 new GpuStreamTextureMsg_FrameAvailable(route_id_)); | |
208 } | |
209 } | |
210 | |
211 gfx::Size StreamTexture::GetSize() { | |
212 return size_; | |
213 } | |
214 | |
215 unsigned StreamTexture::GetInternalFormat() { | |
216 return GL_RGBA; | |
217 } | |
218 | |
219 bool StreamTexture::OnMessageReceived(const IPC::Message& message) { | |
220 bool handled = true; | |
221 IPC_BEGIN_MESSAGE_MAP(StreamTexture, message) | |
222 IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_StartListening, OnStartListening) | |
223 IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_EstablishPeer, OnEstablishPeer) | |
224 IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_SetSize, OnSetSize) | |
225 IPC_MESSAGE_UNHANDLED(handled = false) | |
226 IPC_END_MESSAGE_MAP() | |
227 | |
228 DCHECK(handled); | |
229 return handled; | |
230 } | |
231 | |
232 void StreamTexture::OnStartListening() { | |
233 DCHECK(!has_listener_); | |
234 has_listener_ = true; | |
235 } | |
236 | |
237 void StreamTexture::OnEstablishPeer(int32_t primary_id, int32_t secondary_id) { | |
238 if (!owner_stub_) | |
239 return; | |
240 | |
241 base::ProcessHandle process = owner_stub_->channel()->GetClientPID(); | |
242 | |
243 gpu::SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer( | |
244 process, surface_texture_, primary_id, secondary_id); | |
245 } | |
246 | |
247 bool StreamTexture::BindTexImage(unsigned target) { | |
248 NOTREACHED(); | |
249 return false; | |
250 } | |
251 | |
252 void StreamTexture::ReleaseTexImage(unsigned target) { | |
253 NOTREACHED(); | |
254 } | |
255 | |
256 bool StreamTexture::CopyTexSubImage(unsigned target, | |
257 const gfx::Point& offset, | |
258 const gfx::Rect& rect) { | |
259 return false; | |
260 } | |
261 | |
262 bool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, | |
263 int z_order, | |
264 gfx::OverlayTransform transform, | |
265 const gfx::Rect& bounds_rect, | |
266 const gfx::RectF& crop_rect) { | |
267 NOTREACHED(); | |
268 return false; | |
269 } | |
270 | |
271 void StreamTexture::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, | |
272 uint64_t process_tracing_id, | |
273 const std::string& dump_name) { | |
274 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 | |
275 } | |
276 | |
277 } // namespace content | |
OLD | NEW |