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