OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" | 5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" |
6 | 6 |
7 #include <GLES2/gl2.h> | 7 #include <GLES2/gl2.h> |
8 #include <GLES2/gl2ext.h> | 8 #include <GLES2/gl2ext.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "content/child/child_thread.h" | 11 #include "content/child/child_thread.h" |
12 #include "content/common/gpu/client/context_provider_command_buffer.h" | 12 #include "content/common/gpu/client/context_provider_command_buffer.h" |
13 #include "content/common/gpu/client/gpu_channel_host.h" | 13 #include "content/common/gpu/client/gpu_channel_host.h" |
14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" | 14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" |
15 #include "content/renderer/render_thread_impl.h" | 15 #include "content/renderer/render_thread_impl.h" |
16 #include "gpu/command_buffer/client/gles2_implementation.h" | 16 #include "gpu/command_buffer/client/gles2_implementation.h" |
17 #include "third_party/skia/include/core/SkBitmap.h" | |
17 #include "third_party/skia/include/core/SkPixelRef.h" | 18 #include "third_party/skia/include/core/SkPixelRef.h" |
18 | 19 |
19 namespace content { | 20 namespace content { |
20 | 21 |
21 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} | 22 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} |
22 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( | 23 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories( |
23 GpuChannelHost* gpu_channel_host, | 24 GpuChannelHost* gpu_channel_host, |
24 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) | 25 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) |
25 : message_loop_( | 26 : message_loop_( |
26 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), | 27 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()), |
27 gpu_channel_host_(gpu_channel_host), | 28 gpu_channel_host_(gpu_channel_host), |
28 context_provider_(context_provider), | 29 context_provider_(context_provider), |
29 thread_safe_sender_(ChildThread::current()->thread_safe_sender()), | 30 thread_safe_sender_(ChildThread::current()->thread_safe_sender()) { |
30 aborted_waiter_(true, false), | |
31 message_loop_async_waiter_(false, false) { | |
32 // |context_provider_| is only required to support HW-accelerated decode. | 31 // |context_provider_| is only required to support HW-accelerated decode. |
33 if (!context_provider_) | 32 if (!context_provider_) |
34 return; | 33 return; |
35 | 34 |
36 if (message_loop_->BelongsToCurrentThread()) { | 35 if (message_loop_->BelongsToCurrentThread()) { |
Ami GONE FROM CHROMIUM
2013/10/22 17:21:19
This is never the case, right?
But I guess you wan
sheu
2013/10/24 01:16:39
Superseded (see below)
| |
37 AsyncBindContext(); | 36 AsyncBindContext(); |
38 message_loop_async_waiter_.Reset(); | |
39 return; | 37 return; |
40 } | 38 } |
41 // Wait for the context to be acquired. | 39 // Wait for the context to be acquired. |
wuchengli
2013/10/21 05:59:01
Update or remove the comment. This doesn't wait an
sheu
2013/10/24 01:16:39
Superseded (see below)
| |
42 message_loop_->PostTask( | 40 message_loop_->PostTask( |
43 FROM_HERE, | 41 FROM_HERE, |
44 base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncBindContext, | 42 base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncBindContext, |
Ami GONE FROM CHROMIUM
2013/10/22 17:21:19
Would it make sense to have RenderThreadImpl::GetG
sheu
2013/10/24 01:16:39
I'll do that actually. And along the way undo a p
| |
45 // Unretained to avoid ref/deref'ing |*this|, which is not yet | 43 this)); |
46 // stored in a scoped_refptr. Safe because the Wait() below | |
47 // keeps us alive until this task completes. | |
48 base::Unretained(this))); | |
49 message_loop_async_waiter_.Wait(); | |
50 } | 44 } |
51 | 45 |
52 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories() | |
53 : aborted_waiter_(true, false), | |
54 message_loop_async_waiter_(false, false) {} | |
55 | |
56 WebGraphicsContext3DCommandBufferImpl* | 46 WebGraphicsContext3DCommandBufferImpl* |
57 RendererGpuVideoAcceleratorFactories::GetContext3d() { | 47 RendererGpuVideoAcceleratorFactories::GetContext3d() { |
58 DCHECK(message_loop_->BelongsToCurrentThread()); | 48 DCHECK(message_loop_->BelongsToCurrentThread()); |
59 if (!context_provider_) | 49 if (!context_provider_) |
60 return NULL; | 50 return NULL; |
61 WebGraphicsContext3DCommandBufferImpl* context = | 51 WebGraphicsContext3DCommandBufferImpl* context = |
62 context_provider_->Context3d(); | 52 context_provider_->Context3d(); |
63 if (context->isContextLost()) { | 53 if (context->isContextLost()) { |
64 context_provider_->VerifyContexts(); | 54 context_provider_->VerifyContexts(); |
65 context_provider_ = NULL; | 55 context_provider_ = NULL; |
66 return NULL; | 56 return NULL; |
67 } | 57 } |
68 return context; | 58 return context; |
69 } | 59 } |
70 | 60 |
71 void RendererGpuVideoAcceleratorFactories::AsyncBindContext() { | 61 void RendererGpuVideoAcceleratorFactories::AsyncBindContext() { |
72 DCHECK(message_loop_->BelongsToCurrentThread()); | 62 DCHECK(message_loop_->BelongsToCurrentThread()); |
73 if (!context_provider_->BindToCurrentThread()) | 63 if (!context_provider_->BindToCurrentThread()) |
74 context_provider_ = NULL; | 64 context_provider_ = NULL; |
75 message_loop_async_waiter_.Signal(); | |
76 } | 65 } |
77 | 66 |
78 scoped_ptr<media::VideoDecodeAccelerator> | 67 scoped_ptr<media::VideoDecodeAccelerator> |
79 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( | 68 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( |
80 media::VideoCodecProfile profile, | 69 media::VideoCodecProfile profile, |
81 media::VideoDecodeAccelerator::Client* client) { | 70 media::VideoDecodeAccelerator::Client* client) { |
82 if (message_loop_->BelongsToCurrentThread()) { | 71 DCHECK(message_loop_->BelongsToCurrentThread()); |
83 AsyncCreateVideoDecodeAccelerator(profile, client); | 72 |
84 message_loop_async_waiter_.Reset(); | 73 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
85 return vda_.Pass(); | 74 if (context && context->GetCommandBufferProxy()) { |
75 return gpu_channel_host_->CreateVideoDecoder( | |
76 context->GetCommandBufferProxy()->GetRouteID(), profile, client); | |
86 } | 77 } |
87 // The VDA is returned in the vda_ member variable by the | |
88 // AsyncCreateVideoDecodeAccelerator() function. | |
89 message_loop_->PostTask(FROM_HERE, | |
90 base::Bind(&RendererGpuVideoAcceleratorFactories:: | |
91 AsyncCreateVideoDecodeAccelerator, | |
92 this, | |
93 profile, | |
94 client)); | |
95 | 78 |
96 base::WaitableEvent* objects[] = {&aborted_waiter_, | 79 return scoped_ptr<media::VideoDecodeAccelerator>(); |
97 &message_loop_async_waiter_}; | |
98 if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) { | |
99 // If we are aborting and the VDA is created by the | |
100 // AsyncCreateVideoDecodeAccelerator() function later we need to ensure | |
101 // that it is destroyed on the same thread. | |
102 message_loop_->PostTask(FROM_HERE, | |
103 base::Bind(&RendererGpuVideoAcceleratorFactories:: | |
104 AsyncDestroyVideoDecodeAccelerator, | |
105 this)); | |
106 return scoped_ptr<media::VideoDecodeAccelerator>(); | |
107 } | |
108 return vda_.Pass(); | |
109 } | 80 } |
110 | 81 |
111 scoped_ptr<media::VideoEncodeAccelerator> | 82 scoped_ptr<media::VideoEncodeAccelerator> |
112 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( | 83 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( |
113 media::VideoEncodeAccelerator::Client* client) { | 84 media::VideoEncodeAccelerator::Client* client) { |
114 DCHECK(message_loop_->BelongsToCurrentThread()); | 85 DCHECK(message_loop_->BelongsToCurrentThread()); |
115 | 86 |
116 return gpu_channel_host_->CreateVideoEncoder(client); | 87 return gpu_channel_host_->CreateVideoEncoder(client); |
117 } | 88 } |
118 | 89 |
119 void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator( | |
120 media::VideoCodecProfile profile, | |
121 media::VideoDecodeAccelerator::Client* client) { | |
122 DCHECK(message_loop_->BelongsToCurrentThread()); | |
123 | |
124 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | |
125 if (context && context->GetCommandBufferProxy()) { | |
126 vda_ = gpu_channel_host_->CreateVideoDecoder( | |
127 context->GetCommandBufferProxy()->GetRouteID(), profile, client); | |
128 } | |
129 message_loop_async_waiter_.Signal(); | |
130 } | |
131 | |
132 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( | 90 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( |
133 int32 count, | 91 int32 count, |
134 const gfx::Size& size, | 92 const gfx::Size& size, |
135 std::vector<uint32>* texture_ids, | 93 std::vector<uint32>* texture_ids, |
136 std::vector<gpu::Mailbox>* texture_mailboxes, | 94 std::vector<gpu::Mailbox>* texture_mailboxes, |
137 uint32 texture_target) { | 95 uint32 texture_target) { |
138 DCHECK(message_loop_->BelongsToCurrentThread()); | 96 DCHECK(message_loop_->BelongsToCurrentThread()); |
139 DCHECK(texture_target); | 97 DCHECK(texture_target); |
140 | 98 |
141 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 99 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 if (!context) | 156 if (!context) |
199 return; | 157 return; |
200 | 158 |
201 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 159 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
202 gles2->WaitSyncPointCHROMIUM(sync_point); | 160 gles2->WaitSyncPointCHROMIUM(sync_point); |
203 } | 161 } |
204 | 162 |
205 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, | 163 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, |
206 const gfx::Size& size, | 164 const gfx::Size& size, |
207 const SkBitmap& pixels) { | 165 const SkBitmap& pixels) { |
208 // SkBitmaps use the SkPixelRef object to refcount the underlying pixels. | 166 DCHECK(message_loop_->BelongsToCurrentThread()); |
209 // Multiple SkBitmaps can share a SkPixelRef instance. We use this to | |
210 // ensure that the underlying pixels in the SkBitmap passed in remain valid | |
211 // until the AsyncReadPixels() call completes. | |
212 read_pixels_bitmap_.setPixelRef(pixels.pixelRef()); | |
213 | 167 |
214 if (!message_loop_->BelongsToCurrentThread()) { | |
215 message_loop_->PostTask( | |
216 FROM_HERE, | |
217 base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels, | |
218 this, | |
219 texture_id, | |
220 size)); | |
221 base::WaitableEvent* objects[] = {&aborted_waiter_, | |
222 &message_loop_async_waiter_}; | |
223 if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) | |
224 return; | |
225 } else { | |
226 AsyncReadPixels(texture_id, size); | |
227 message_loop_async_waiter_.Reset(); | |
228 } | |
229 read_pixels_bitmap_.setPixelRef(NULL); | |
230 } | |
231 | |
232 void RendererGpuVideoAcceleratorFactories::AsyncReadPixels( | |
233 uint32 texture_id, | |
234 const gfx::Size& size) { | |
235 DCHECK(message_loop_->BelongsToCurrentThread()); | |
236 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 168 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
237 if (!context) { | 169 if (!context) |
238 message_loop_async_waiter_.Signal(); | |
239 return; | 170 return; |
240 } | |
241 | 171 |
242 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 172 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
243 | 173 |
244 GLuint tmp_texture; | 174 GLuint tmp_texture; |
245 gles2->GenTextures(1, &tmp_texture); | 175 gles2->GenTextures(1, &tmp_texture); |
246 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); | 176 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); |
247 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 177 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
248 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 178 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
249 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 179 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
250 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 180 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
251 context->copyTextureCHROMIUM( | 181 context->copyTextureCHROMIUM( |
252 GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE); | 182 GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE); |
253 | 183 |
254 GLuint fb; | 184 GLuint fb; |
255 gles2->GenFramebuffers(1, &fb); | 185 gles2->GenFramebuffers(1, &fb); |
256 gles2->BindFramebuffer(GL_FRAMEBUFFER, fb); | 186 gles2->BindFramebuffer(GL_FRAMEBUFFER, fb); |
257 gles2->FramebufferTexture2D( | 187 gles2->FramebufferTexture2D( |
258 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0); | 188 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_texture, 0); |
259 gles2->PixelStorei(GL_PACK_ALIGNMENT, 4); | 189 gles2->PixelStorei(GL_PACK_ALIGNMENT, 4); |
260 gles2->ReadPixels(0, | 190 gles2->ReadPixels(0, |
261 0, | 191 0, |
262 size.width(), | 192 size.width(), |
263 size.height(), | 193 size.height(), |
264 GL_BGRA_EXT, | 194 GL_BGRA_EXT, |
265 GL_UNSIGNED_BYTE, | 195 GL_UNSIGNED_BYTE, |
266 read_pixels_bitmap_.pixelRef()->pixels()); | 196 pixels.pixelRef()->pixels()); |
267 gles2->DeleteFramebuffers(1, &fb); | 197 gles2->DeleteFramebuffers(1, &fb); |
268 gles2->DeleteTextures(1, &tmp_texture); | 198 gles2->DeleteTextures(1, &tmp_texture); |
269 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 199 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
270 message_loop_async_waiter_.Signal(); | |
271 } | 200 } |
272 | 201 |
273 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( | 202 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( |
274 size_t size) { | 203 size_t size) { |
275 DCHECK(message_loop_->BelongsToCurrentThread()); | 204 DCHECK(message_loop_->BelongsToCurrentThread()); |
276 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); | 205 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); |
277 } | 206 } |
278 | 207 |
279 scoped_refptr<base::MessageLoopProxy> | 208 scoped_refptr<base::MessageLoopProxy> |
280 RendererGpuVideoAcceleratorFactories::GetMessageLoop() { | 209 RendererGpuVideoAcceleratorFactories::GetMessageLoop() { |
281 return message_loop_; | 210 return message_loop_; |
282 } | 211 } |
283 | 212 |
284 void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); } | |
285 | |
286 bool RendererGpuVideoAcceleratorFactories::IsAborted() { | |
287 return aborted_waiter_.IsSignaled(); | |
288 } | |
289 | |
290 scoped_refptr<RendererGpuVideoAcceleratorFactories> | |
291 RendererGpuVideoAcceleratorFactories::Clone() { | |
292 scoped_refptr<RendererGpuVideoAcceleratorFactories> factories = | |
293 new RendererGpuVideoAcceleratorFactories(); | |
294 factories->message_loop_ = message_loop_; | |
295 factories->gpu_channel_host_ = gpu_channel_host_; | |
296 factories->context_provider_ = context_provider_; | |
297 factories->thread_safe_sender_ = thread_safe_sender_; | |
298 return factories; | |
299 } | |
300 | |
301 void | |
302 RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() { | |
303 // OK to release because Destroy() will delete the VDA instance. | |
304 if (vda_) | |
305 vda_.release()->Destroy(); | |
306 } | |
307 | |
308 } // namespace content | 213 } // namespace content |
OLD | NEW |