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. 4 5 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" 6 7 #include <GLES2/gl2.h> 8 #include <GLES2/gl2ext.h> 9 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" 21 22 namespace content { 23 24 // static 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 34 // within. 35 message_loop_proxy->PostTask( 36 FROM_HERE, 37 base::Bind(&RendererGpuVideoAcceleratorFactories::BindContext, 38 factories)); 39 return factories; 40 } 41 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()) {} 50 51 RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {} 52 53 void RendererGpuVideoAcceleratorFactories::BindContext() { 54 DCHECK(task_runner_->BelongsToCurrentThread()); 55 if (!context_provider_->BindToCurrentThread()) 56 context_provider_ = NULL; 57 } 58 59 WebGraphicsContext3DCommandBufferImpl* 60 RendererGpuVideoAcceleratorFactories::GetContext3d() { 61 DCHECK(task_runner_->BelongsToCurrentThread()); 62 if (!context_provider_) 63 return NULL; 64 if (context_provider_->IsContextLost()) { 65 context_provider_->VerifyContexts(); 66 context_provider_ = NULL; 67 return NULL; 68 } 69 return context_provider_->WebContext3D(); 70 } 71 72 scoped_ptr<media::VideoDecodeAccelerator> 73 RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() { 74 DCHECK(task_runner_->BelongsToCurrentThread()); 75 76 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); 77 if (context && context->GetCommandBufferProxy()) { 78 return gpu_channel_host_->CreateVideoDecoder( 79 context->GetCommandBufferProxy()->GetRouteID()); 80 } 81 82 return scoped_ptr<media::VideoDecodeAccelerator>(); 83 } 84 85 scoped_ptr<media::VideoEncodeAccelerator> 86 RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator() { 87 DCHECK(task_runner_->BelongsToCurrentThread()); 88 89 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); 90 if (context && context->GetCommandBufferProxy()) { 91 return gpu_channel_host_->CreateVideoEncoder( 92 context->GetCommandBufferProxy()->GetRouteID()); 93 } 94 95 return scoped_ptr<media::VideoEncodeAccelerator>(); 96 } 97 98 bool RendererGpuVideoAcceleratorFactories::CreateTextures( 99 int32 count, 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); 106 107 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); 108 if (!context) 109 return false; 110 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, 125 0, 126 GL_RGBA, 127 size.width(), 128 size.height(), 129 0, 130 GL_RGBA, 131 GL_UNSIGNED_BYTE, 132 NULL); 133 } 134 gles2->GenMailboxCHROMIUM(texture_mailboxes->at(i).name); 135 gles2->ProduceTextureCHROMIUM(texture_target, 136 texture_mailboxes->at(i).name); 137 } 138 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)); 145 return true; 146 } 147 148 void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) { 149 DCHECK(task_runner_->BelongsToCurrentThread()); 150 151 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); 152 if (!context) 153 return; 154 155 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); 156 gles2->DeleteTextures(1, &texture_id); 157 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); 158 } 159 160 void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) { 161 DCHECK(task_runner_->BelongsToCurrentThread()); 162 163 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); 164 if (!context) 165 return; 166 167 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); 168 gles2->WaitSyncPointCHROMIUM(sync_point); 169 170 // Callers expect the WaitSyncPoint to affect the next IPCs. Make sure to 171 // flush the command buffers to ensure that. 172 gles2->ShallowFlushCHROMIUM(); 173 } 174 175 void RendererGpuVideoAcceleratorFactories::ReadPixels( 176 uint32 texture_id, 177 const gfx::Rect& visible_rect, 178 const SkBitmap& pixels) { 179 DCHECK(task_runner_->BelongsToCurrentThread()); 180 181 WebGraphicsContext3DCommandBufferImpl* context = GetContext3d(); 182 if (!context) 183 return; 184 185 gpu::gles2::GLES2Implementation* gles2 = context->GetImplementation(); 186 187 GLuint tmp_texture; 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); 196 197 GLuint fb; 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); 203 204 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ 205 SK_A32_SHIFT == 24 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; 214 } 215 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ 216 SK_A32_SHIFT == 24 217 GLenum skia_format = GL_RGBA; 218 GLenum read_format = GL_RGBA; 219 #else 220 #error Unexpected Skia ARGB_8888 layout! 221 #endif 222 gles2->ReadPixels(visible_rect.x(), 223 visible_rect.y(), 224 visible_rect.width(), 225 visible_rect.height(), 226 read_format, 227 GL_UNSIGNED_BYTE, 228 pixels.pixelRef()->pixels()); 229 gles2->DeleteFramebuffers(1, &fb); 230 gles2->DeleteTextures(1, &tmp_texture); 231 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) | 244 (a << SK_A32_SHIFT); 245 } 246 } 247 248 DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR)); 249 } 250 251 base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( 252 size_t size) { 253 DCHECK(task_runner_->BelongsToCurrentThread()); 254 return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); 255 } 256 257 scoped_refptr<base::SingleThreadTaskRunner> 258 RendererGpuVideoAcceleratorFactories::GetTaskRunner() { 259 return task_runner_; 260 } 261 262 } // namespace content 263