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
3 // found in the LICENSE file.
5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
8 #include <GLES2/gl2ext.h>
10 #include "base/bind.h"
11 #include "content/child/child_thread.h"
12 #include "content/common/gpu/client/context_provider_command_buffer.h"
13 #include "content/common/gpu/client/gl_helper.h"
14 #include "content/common/gpu/client/gpu_channel_host.h"
15 #include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
16 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "gpu/command_buffer/client/gles2_implementation.h"
19 #include "media/video/video_decode_accelerator.h"
20 #include "media/video/video_encode_accelerator.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "third_party/skia/include/core/SkPixelRef.h"
27 scoped_refptr<RendererGpuVideoAcceleratorFactories>
28 RendererGpuVideoAcceleratorFactories::Create(
29 GpuChannelHost* gpu_channel_host,
30 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
31 const scoped_refptr<ContextProviderCommandBuffer>& context_provider) {
32 scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
33 new RendererGpuVideoAcceleratorFactories(
34 gpu_channel_host, task_runner, context_provider);
35 // Post task from outside constructor, since AddRef()/Release() is unsafe from
37 task_runner->PostTask(
39 base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext,
44 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
45 GpuChannelHost* gpu_channel_host,
46 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
47 const scoped_refptr<ContextProviderCommandBuffer>& context_provider)
48 : task_runner_(task_runner),
49 gpu_channel_host_(gpu_channel_host),
50 context_provider_(context_provider),
51 thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
53 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
55 void RendererGpuVideoAcceleratorFactories::BindContext() {
56 DCHECK(task_runner_->BelongsToCurrentThread());
57 if (!context_provider_->BindToCurrentThread())
58 context_provider_ = NULL;
61 WebGraphicsContext3DCommandBufferImpl*
62 RendererGpuVideoAcceleratorFactories::GetContext3d() {
63 DCHECK(task_runner_->BelongsToCurrentThread());
64 if (!context_provider_.get())
66 if (context_provider_->IsContextLost()) {
67 context_provider_->VerifyContexts();
68 context_provider_ = NULL;
69 gl_helper_.reset(NULL);
72 return context_provider_->WebContext3D();
75 GLHelper* RendererGpuVideoAcceleratorFactories::GetGLHelper() {
79 if (gl_helper_.get() == NULL) {
80 gl_helper_.reset(new GLHelper(GetContext3d()->GetImplementation(),
81 GetContext3d()->GetContextSupport()));
84 return gl_helper_.get();
87 scoped_ptr<media::VideoDecodeAccelerator>
88 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() {
89 DCHECK(task_runner_->BelongsToCurrentThread());
91 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
92 if (context && context->GetCommandBufferProxy()) {
93 return gpu_channel_host_->CreateVideoDecoder(
94 context->GetCommandBufferProxy()->GetRouteID());
97 return scoped_ptr<media::VideoDecodeAccelerator>();
100 scoped_ptr<media::VideoEncodeAccelerator>
101 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() {
102 DCHECK(task_runner_->BelongsToCurrentThread());
104 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
105 if (context && context->GetCommandBufferProxy()) {
106 return gpu_channel_host_->CreateVideoEncoder(
107 context->GetCommandBufferProxy()->GetRouteID());
110 return scoped_ptr<media::VideoEncodeAccelerator>();
113 bool RendererGpuVideoAcceleratorFactories::CreateTextures(
115 const gfx::Size& size,
116 std::vector<uint32>* texture_ids,
117 std::vector<gpu::Mailbox>* texture_mailboxes,
118 uint32 texture_target) {
119 DCHECK(task_runner_->BelongsToCurrentThread());
120 DCHECK(texture_target);
122 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
126 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
127 texture_ids->resize(count);
128 texture_mailboxes->resize(count);
129 gles2->GenTextures(count, &texture_ids->at(0));
130 for (int i = 0; i < count; ++i) {
131 gles2->ActiveTexture(GL_TEXTURE0);
132 uint32 texture_id = texture_ids->at(i);
133 gles2->BindTexture(texture_target, texture_id);
134 gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
135 gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
136 gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
137 gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
138 if (texture_target == GL_TEXTURE_2D) {
139 gles2->TexImage2D(texture_target,
149 gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name);
150 gles2->ProduceTextureCHROMIUM(texture_target,
151 texture_mailboxes->at(i).name);
154 // We need ShallowFlushCHROMIUM() here to order the command buffer commands
155 // with respect to IPC to the GPU process, to guarantee that the decoder in
156 // the GPU process can use these textures as soon as it receives IPC
157 // notification of them.
158 gles2->ShallowFlushCHROMIUM();
159 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
163 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
164 DCHECK(task_runner_->BelongsToCurrentThread());
166 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
170 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
171 gles2->DeleteTextures(1, &texture_id);
172 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
175 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
176 DCHECK(task_runner_->BelongsToCurrentThread());
178 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
182 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation();
183 gles2->WaitSyncPointCHROMIUM(sync_point);
185 // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
186 // flush the command buffers to ensure that.
187 gles2->ShallowFlushCHROMIUM();
190 void RendererGpuVideoAcceleratorFactories::ReadPixels(
192 const gfx::Rect& visible_rect,
193 const SkBitmap& pixels) {
194 DCHECK(task_runner_->BelongsToCurrentThread());
196 GLHelper* gl_helper = GetGLHelper();
197 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d();
199 if (!gl_helper || !context)
202 // Copy texture from texture_id to tmp_texture as texture might be external
203 // (GL_TEXTURE_EXTERNAL_OES)
205 tmp_texture = gl_helper->CreateTexture();
206 context->copyTextureCHROMIUM(
207 GL_TEXTURE_2D, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
209 unsigned char* pixel_data =
210 static_cast<unsigned char*>(pixels.pixelRef()->pixels());
212 if (gl_helper->IsReadbackConfigSupported(pixels.colorType())) {
213 gl_helper->ReadbackTextureSync(
214 tmp_texture, visible_rect, pixel_data, pixels.colorType());
215 } else if (pixels.colorType() == kN32_SkColorType) {
216 gl_helper->ReadbackTextureSync(
217 tmp_texture, visible_rect, pixel_data, kRGBA_8888_SkColorType);
219 int pixel_count = visible_rect.width() * visible_rect.height();
220 uint32_t* pixels_ptr = static_cast<uint32_t*>(pixels.pixelRef()->pixels());
221 for (int i = 0; i < pixel_count; ++i) {
222 uint32_t r = pixels_ptr[i] & 0xFF;
223 uint32_t g = (pixels_ptr[i] >> 8) & 0xFF;
224 uint32_t b = (pixels_ptr[i] >> 16) & 0xFF;
225 uint32_t a = (pixels_ptr[i] >> 24) & 0xFF;
226 pixels_ptr[i] = (r << SK_R32_SHIFT) |
227 (g << SK_G32_SHIFT) |
228 (b << SK_B32_SHIFT) |
235 gl_helper->DeleteTexture(tmp_texture);
238 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
240 DCHECK(task_runner_->BelongsToCurrentThread());
241 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get());
244 scoped_refptr<base::SingleThreadTaskRunner>
245 RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
249 std::vector<media::VideoEncodeAccelerator::SupportedProfile>
250 RendererGpuVideoAcceleratorFactories::
251 GetVideoEncodeAcceleratorSupportedProfiles() {
252 return GpuVideoEncodeAcceleratorHost::ConvertGpuToMediaProfiles(
253 gpu_channel_host_->gpu_info()
254 .video_encode_accelerator_supported_profiles);
257 } // namespace content