| 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, |
| 25 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
| 24 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) | 26 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) |
| 25 : message_loop_( | 27 : message_loop_proxy_(message_loop_proxy), |
| 26 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. | |
| 33 if (!context_provider_) | |
| 34 return; | |
| 35 | |
| 36 if (message_loop_->BelongsToCurrentThread()) { | |
| 37 AsyncBindContext(); | |
| 38 message_loop_async_waiter_.Reset(); | |
| 39 return; | |
| 40 } | |
| 41 // Wait for the context to be acquired. | |
| 42 message_loop_->PostTask( | |
| 43 FROM_HERE, | |
| 44 base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncBindContext, | |
| 45 // Unretained to avoid ref/deref'ing |*this|, which is not yet | |
| 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 } | |
| 51 | |
| 52 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories() | |
| 53 : aborted_waiter_(true, false), | |
| 54 message_loop_async_waiter_(false, false) {} | |
| 55 | 31 |
| 56 WebGraphicsContext3DCommandBufferImpl* | 32 WebGraphicsContext3DCommandBufferImpl* |
| 57 RendererGpuVideoAcceleratorFactories::GetContext3d() { | 33 RendererGpuVideoAcceleratorFactories::GetContext3d() { |
| 58 DCHECK(message_loop_->BelongsToCurrentThread()); | 34 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 59 if (!context_provider_) | 35 if (!context_provider_) |
| 60 return NULL; | 36 return NULL; |
| 61 WebGraphicsContext3DCommandBufferImpl* context = | 37 WebGraphicsContext3DCommandBufferImpl* context = |
| 62 context_provider_->Context3d(); | 38 context_provider_->Context3d(); |
| 63 if (context->isContextLost()) { | 39 if (context->isContextLost()) { |
| 64 context_provider_->VerifyContexts(); | 40 context_provider_->VerifyContexts(); |
| 65 context_provider_ = NULL; | 41 context_provider_ = NULL; |
| 66 return NULL; | 42 return NULL; |
| 67 } | 43 } |
| 68 return context; | 44 return context; |
| 69 } | 45 } |
| 70 | 46 |
| 71 void RendererGpuVideoAcceleratorFactories::AsyncBindContext() { | |
| 72 DCHECK(message_loop_->BelongsToCurrentThread()); | |
| 73 if (!context_provider_->BindToCurrentThread()) | |
| 74 context_provider_ = NULL; | |
| 75 message_loop_async_waiter_.Signal(); | |
| 76 } | |
| 77 | |
| 78 scoped_ptr<media::VideoDecodeAccelerator> | 47 scoped_ptr<media::VideoDecodeAccelerator> |
| 79 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( | 48 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator( |
| 80 media::VideoCodecProfile profile, | 49 media::VideoCodecProfile profile, |
| 81 media::VideoDecodeAccelerator::Client* client) { | 50 media::VideoDecodeAccelerator::Client* client) { |
| 82 if (message_loop_->BelongsToCurrentThread()) { | 51 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 83 AsyncCreateVideoDecodeAccelerator(profile, client); | 52 |
| 84 message_loop_async_waiter_.Reset(); | 53 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
| 85 return vda_.Pass(); | 54 if (context && context->GetCommandBufferProxy()) { |
| 55 return gpu_channel_host_->CreateVideoDecoder( |
| 56 context->GetCommandBufferProxy()->GetRouteID(), profile, client); |
| 86 } | 57 } |
| 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 | 58 |
| 96 base::WaitableEvent* objects[] = {&aborted_waiter_, | 59 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 } | 60 } |
| 110 | 61 |
| 111 scoped_ptr<media::VideoEncodeAccelerator> | 62 scoped_ptr<media::VideoEncodeAccelerator> |
| 112 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( | 63 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator( |
| 113 media::VideoEncodeAccelerator::Client* client) { | 64 media::VideoEncodeAccelerator::Client* client) { |
| 114 DCHECK(message_loop_->BelongsToCurrentThread()); | 65 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 115 | 66 |
| 116 return gpu_channel_host_->CreateVideoEncoder(client); | 67 return gpu_channel_host_->CreateVideoEncoder(client); |
| 117 } | 68 } |
| 118 | 69 |
| 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( | 70 uint32 RendererGpuVideoAcceleratorFactories::CreateTextures( |
| 133 int32 count, | 71 int32 count, |
| 134 const gfx::Size& size, | 72 const gfx::Size& size, |
| 135 std::vector<uint32>* texture_ids, | 73 std::vector<uint32>* texture_ids, |
| 136 std::vector<gpu::Mailbox>* texture_mailboxes, | 74 std::vector<gpu::Mailbox>* texture_mailboxes, |
| 137 uint32 texture_target) { | 75 uint32 texture_target) { |
| 138 DCHECK(message_loop_->BelongsToCurrentThread()); | 76 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 139 DCHECK(texture_target); | 77 DCHECK(texture_target); |
| 140 | 78 |
| 141 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 79 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
| 142 if (!context) | 80 if (!context) |
| 143 return 0; | 81 return 0; |
| 144 | 82 |
| 145 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 83 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
| 146 texture_ids->resize(count); | 84 texture_ids->resize(count); |
| 147 texture_mailboxes->resize(count); | 85 texture_mailboxes->resize(count); |
| 148 gles2->GenTextures(count, &texture_ids->at(0)); | 86 gles2->GenTextures(count, &texture_ids->at(0)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 173 // We need a glFlush here to guarantee the decoder (in the GPU process) can | 111 // We need a glFlush here to guarantee the decoder (in the GPU process) can |
| 174 // use the texture ids we return here. Since textures are expected to be | 112 // use the texture ids we return here. Since textures are expected to be |
| 175 // reused, this should not be unacceptably expensive. | 113 // reused, this should not be unacceptably expensive. |
| 176 gles2->Flush(); | 114 gles2->Flush(); |
| 177 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 115 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
| 178 | 116 |
| 179 return gles2->InsertSyncPointCHROMIUM(); | 117 return gles2->InsertSyncPointCHROMIUM(); |
| 180 } | 118 } |
| 181 | 119 |
| 182 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) { | 120 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) { |
| 183 DCHECK(message_loop_->BelongsToCurrentThread()); | 121 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 184 | 122 |
| 185 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 123 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
| 186 if (!context) | 124 if (!context) |
| 187 return; | 125 return; |
| 188 | 126 |
| 189 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 127 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
| 190 gles2->DeleteTextures(1, &texture_id); | 128 gles2->DeleteTextures(1, &texture_id); |
| 191 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 129 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
| 192 } | 130 } |
| 193 | 131 |
| 194 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) { | 132 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) { |
| 195 DCHECK(message_loop_->BelongsToCurrentThread()); | 133 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 196 | 134 |
| 197 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); | 135 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
| 198 if (!context) | 136 if (!context) |
| 199 return; | 137 return; |
| 200 | 138 |
| 201 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 139 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
| 202 gles2->WaitSyncPointCHROMIUM(sync_point); | 140 gles2->WaitSyncPointCHROMIUM(sync_point); |
| 203 } | 141 } |
| 204 | 142 |
| 205 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, | 143 void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id, |
| 206 const gfx::Size& size, | 144 const gfx::Size& size, |
| 207 const SkBitmap& pixels) { | 145 const SkBitmap& pixels) { |
| 208 // SkBitmaps use the SkPixelRef object to refcount the underlying pixels. | 146 DCHECK(message_loop_proxy_->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 | 147 |
| 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(); | 148 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); |
| 237 if (!context) { | 149 if (!context) |
| 238 message_loop_async_waiter_.Signal(); | |
| 239 return; | 150 return; |
| 240 } | |
| 241 | 151 |
| 242 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); | 152 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); |
| 243 | 153 |
| 244 GLuint tmp_texture; | 154 GLuint tmp_texture; |
| 245 gles2->GenTextures(1, &tmp_texture); | 155 gles2->GenTextures(1, &tmp_texture); |
| 246 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); | 156 gles2->BindTexture(GL_TEXTURE_2D, tmp_texture); |
| 247 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 157 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 248 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 158 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); | 159 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); | 160 gles2->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 265 GLenum skia_format = GL_RGBA; | 175 GLenum skia_format = GL_RGBA; |
| 266 #else | 176 #else |
| 267 #error Unexpected Skia ARGB_8888 layout! | 177 #error Unexpected Skia ARGB_8888 layout! |
| 268 #endif | 178 #endif |
| 269 gles2->ReadPixels(0, | 179 gles2->ReadPixels(0, |
| 270 0, | 180 0, |
| 271 size.width(), | 181 size.width(), |
| 272 size.height(), | 182 size.height(), |
| 273 skia_format, | 183 skia_format, |
| 274 GL_UNSIGNED_BYTE, | 184 GL_UNSIGNED_BYTE, |
| 275 read_pixels_bitmap_.pixelRef()->pixels()); | 185 pixels.pixelRef()->pixels()); |
| 276 gles2->DeleteFramebuffers(1, &fb); | 186 gles2->DeleteFramebuffers(1, &fb); |
| 277 gles2->DeleteTextures(1, &tmp_texture); | 187 gles2->DeleteTextures(1, &tmp_texture); |
| 278 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); | 188 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); |
| 279 message_loop_async_waiter_.Signal(); | |
| 280 } | 189 } |
| 281 | 190 |
| 282 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( | 191 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( |
| 283 size_t size) { | 192 size_t size) { |
| 284 DCHECK(message_loop_->BelongsToCurrentThread()); | 193 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 285 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); | 194 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); |
| 286 } | 195 } |
| 287 | 196 |
| 288 scoped_refptr<base::MessageLoopProxy> | 197 scoped_refptr<base::MessageLoopProxy> |
| 289 RendererGpuVideoAcceleratorFactories::GetMessageLoop() { | 198 RendererGpuVideoAcceleratorFactories::GetMessageLoop() { |
| 290 return message_loop_; | 199 return message_loop_proxy_; |
| 291 } | |
| 292 | |
| 293 void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); } | |
| 294 | |
| 295 bool RendererGpuVideoAcceleratorFactories::IsAborted() { | |
| 296 return aborted_waiter_.IsSignaled(); | |
| 297 } | |
| 298 | |
| 299 scoped_refptr<RendererGpuVideoAcceleratorFactories> | |
| 300 RendererGpuVideoAcceleratorFactories::Clone() { | |
| 301 scoped_refptr<RendererGpuVideoAcceleratorFactories> factories = | |
| 302 new RendererGpuVideoAcceleratorFactories(); | |
| 303 factories->message_loop_ = message_loop_; | |
| 304 factories->gpu_channel_host_ = gpu_channel_host_; | |
| 305 factories->context_provider_ = context_provider_; | |
| 306 factories->thread_safe_sender_ = thread_safe_sender_; | |
| 307 return factories; | |
| 308 } | |
| 309 | |
| 310 void | |
| 311 RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() { | |
| 312 // OK to release because Destroy() will delete the VDA instance. | |
| 313 if (vda_) | |
| 314 vda_.release()->Destroy(); | |
| 315 } | 200 } |
| 316 | 201 |
| 317 } // namespace content | 202 } // namespace content |
| OLD | NEW |