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/gpu_channel_host.h"
14 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
15 #include "content/renderer/render_thread_impl.h"
16 #include "gpu/command_buffer/client/gles2_implementation.h"
17 #include "media/video/video_decode_accelerator.h"
18 #include "media/video/video_encode_accelerator.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "third_party/skia/include/core/SkPixelRef.h"
25 scoped_refptr
<RendererGpuVideoAcceleratorFactories
>
26 RendererGpuVideoAcceleratorFactories::Create(
27 GpuChannelHost
* gpu_channel_host
,
28 const scoped_refptr
<base::MessageLoopProxy
>& message_loop_proxy
,
29 const scoped_refptr
<ContextProviderCommandBuffer
>& context_provider
) {
30 scoped_refptr
<RendererGpuVideoAcceleratorFactories
> factories
=
31 new RendererGpuVideoAcceleratorFactories(
32 gpu_channel_host
, message_loop_proxy
, context_provider
);
33 // Post task from outside constructor, since AddRef()/Release() is unsafe from
35 message_loop_proxy
->PostTask(
37 base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext
,
42 RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
43 GpuChannelHost
* gpu_channel_host
,
44 const scoped_refptr
<base::MessageLoopProxy
>& message_loop_proxy
,
45 const scoped_refptr
<ContextProviderCommandBuffer
>& context_provider
)
46 : task_runner_(message_loop_proxy
),
47 gpu_channel_host_(gpu_channel_host
),
48 context_provider_(context_provider
),
49 thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
51 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
53 void RendererGpuVideoAcceleratorFactories::BindContext() {
54 DCHECK(task_runner_
->BelongsToCurrentThread());
55 if (!context_provider_
->BindToCurrentThread())
56 context_provider_
= NULL
;
59 WebGraphicsContext3DCommandBufferImpl
*
60 RendererGpuVideoAcceleratorFactories::GetContext3d() {
61 DCHECK(task_runner_
->BelongsToCurrentThread());
62 if (!context_provider_
)
64 if (context_provider_
->IsContextLost()) {
65 context_provider_
->VerifyContexts();
66 context_provider_
= NULL
;
69 return context_provider_
->WebContext3D();
72 scoped_ptr
<media::VideoDecodeAccelerator
>
73 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() {
74 DCHECK(task_runner_
->BelongsToCurrentThread());
76 WebGraphicsContext3DCommandBufferImpl
* context
= GetContext3d();
77 if (context
&& context
->GetCommandBufferProxy()) {
78 return gpu_channel_host_
->CreateVideoDecoder(
79 context
->GetCommandBufferProxy()->GetRouteID());
82 return scoped_ptr
<media::VideoDecodeAccelerator
>();
85 scoped_ptr
<media::VideoEncodeAccelerator
>
86 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() {
87 DCHECK(task_runner_
->BelongsToCurrentThread());
89 WebGraphicsContext3DCommandBufferImpl
* context
= GetContext3d();
90 if (context
&& context
->GetCommandBufferProxy()) {
91 return gpu_channel_host_
->CreateVideoEncoder(
92 context
->GetCommandBufferProxy()->GetRouteID());
95 return scoped_ptr
<media::VideoEncodeAccelerator
>();
98 bool RendererGpuVideoAcceleratorFactories::CreateTextures(
100 const gfx::Size
& size
,
101 std::vector
<uint32
>* texture_ids
,
102 std::vector
<gpu::Mailbox
>* texture_mailboxes
,
103 uint32 texture_target
) {
104 DCHECK(task_runner_
->BelongsToCurrentThread());
105 DCHECK(texture_target
);
107 WebGraphicsContext3DCommandBufferImpl
* context
= GetContext3d();
111 gpu::gles2::GLES2Implementation
* gles2
= context
->GetImplementation();
112 texture_ids
->resize(count
);
113 texture_mailboxes
->resize(count
);
114 gles2
->GenTextures(count
, &texture_ids
->at(0));
115 for (int i
= 0; i
< count
; ++i
) {
116 gles2
->ActiveTexture(GL_TEXTURE0
);
117 uint32 texture_id
= texture_ids
->at(i
);
118 gles2
->BindTexture(texture_target
, texture_id
);
119 gles2
->TexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
120 gles2
->TexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
121 gles2
->TexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
122 gles2
->TexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
123 if (texture_target
== GL_TEXTURE_2D
) {
124 gles2
->TexImage2D(texture_target
,
134 gles2
->GenMailboxCHROMIUM(texture_mailboxes
->at(i
).name
);
135 gles2
->ProduceTextureCHROMIUM(texture_target
,
136 texture_mailboxes
->at(i
).name
);
139 // We need ShallowFlushCHROMIUM() here to order the command buffer commands
140 // with respect to IPC to the GPU process, to guarantee that the decoder in
141 // the GPU process can use these textures as soon as it receives IPC
142 // notification of them.
143 gles2
->ShallowFlushCHROMIUM();
144 DCHECK_EQ(gles2
->GetError(), static_cast<GLenum
>(GL_NO_ERROR
));
148 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id
) {
149 DCHECK(task_runner_
->BelongsToCurrentThread());
151 WebGraphicsContext3DCommandBufferImpl
* context
= GetContext3d();
155 gpu::gles2::GLES2Implementation
* gles2
= context
->GetImplementation();
156 gles2
->DeleteTextures(1, &texture_id
);
157 DCHECK_EQ(gles2
->GetError(), static_cast<GLenum
>(GL_NO_ERROR
));
160 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point
) {
161 DCHECK(task_runner_
->BelongsToCurrentThread());
163 WebGraphicsContext3DCommandBufferImpl
* context
= GetContext3d();
167 gpu::gles2::GLES2Implementation
* gles2
= context
->GetImplementation();
168 gles2
->WaitSyncPointCHROMIUM(sync_point
);
170 // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to
171 // flush the command buffers to ensure that.
172 gles2
->ShallowFlushCHROMIUM();
175 void RendererGpuVideoAcceleratorFactories::ReadPixels(
177 const gfx::Rect
& visible_rect
,
178 const SkBitmap
& pixels
) {
179 DCHECK(task_runner_
->BelongsToCurrentThread());
181 WebGraphicsContext3DCommandBufferImpl
* context
= GetContext3d();
185 gpu::gles2::GLES2Implementation
* gles2
= context
->GetImplementation();
188 gles2
->GenTextures(1, &tmp_texture
);
189 gles2
->BindTexture(GL_TEXTURE_2D
, tmp_texture
);
190 gles2
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
191 gles2
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
192 gles2
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
193 gles2
->TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
194 context
->copyTextureCHROMIUM(
195 GL_TEXTURE_2D
, texture_id
, tmp_texture
, 0, GL_RGBA
, GL_UNSIGNED_BYTE
);
198 gles2
->GenFramebuffers(1, &fb
);
199 gles2
->BindFramebuffer(GL_FRAMEBUFFER
, fb
);
200 gles2
->FramebufferTexture2D(
201 GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
, GL_TEXTURE_2D
, tmp_texture
, 0);
202 gles2
->PixelStorei(GL_PACK_ALIGNMENT
, 4);
204 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
206 GLenum skia_format
= GL_BGRA_EXT
;
207 GLenum read_format
= GL_BGRA_EXT
;
208 GLint supported_format
= 0;
209 GLint supported_type
= 0;
210 gles2
->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT
, &supported_format
);
211 gles2
->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE
, &supported_type
);
212 if (supported_format
!= GL_BGRA_EXT
|| supported_type
!= GL_UNSIGNED_BYTE
) {
213 read_format
= GL_RGBA
;
215 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
217 GLenum skia_format
= GL_RGBA
;
218 GLenum read_format
= GL_RGBA
;
220 #error Unexpected Skia ARGB_8888 layout!
222 gles2
->ReadPixels(visible_rect
.x(),
224 visible_rect
.width(),
225 visible_rect
.height(),
228 pixels
.pixelRef()->pixels());
229 gles2
->DeleteFramebuffers(1, &fb
);
230 gles2
->DeleteTextures(1, &tmp_texture
);
232 if (skia_format
!= read_format
) {
233 DCHECK(read_format
== GL_RGBA
);
234 int pixel_count
= visible_rect
.width() * visible_rect
.height();
235 uint32_t* pixels_ptr
= static_cast<uint32_t*>(pixels
.pixelRef()->pixels());
236 for (int i
= 0; i
< pixel_count
; ++i
) {
237 uint32_t r
= pixels_ptr
[i
] & 0xFF;
238 uint32_t g
= (pixels_ptr
[i
] >> 8) & 0xFF;
239 uint32_t b
= (pixels_ptr
[i
] >> 16) & 0xFF;
240 uint32_t a
= (pixels_ptr
[i
] >> 24) & 0xFF;
241 pixels_ptr
[i
] = (r
<< SK_R32_SHIFT
) |
242 (g
<< SK_G32_SHIFT
) |
243 (b
<< SK_B32_SHIFT
) |
248 DCHECK_EQ(gles2
->GetError(), static_cast<GLenum
>(GL_NO_ERROR
));
251 base::SharedMemory
* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
253 DCHECK(task_runner_
->BelongsToCurrentThread());
254 return ChildThread::AllocateSharedMemory(size
, thread_safe_sender_
.get());
257 scoped_refptr
<base::SingleThreadTaskRunner
>
258 RendererGpuVideoAcceleratorFactories::GetTaskRunner() {
262 } // namespace content