Chromium Code Reviews| 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 "ui/gl/gl_image_io_surface.h" | 5 #include "ui/gl/gl_image_io_surface.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/callback_helpers.h" | |
| 9 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/mac/bind_objc_block.h" | |
| 12 #include "base/mac/foundation_util.h" | |
|
Daniele Castagna
2016/04/06 20:36:58
Is foundation_util.h included twice?
ccameron
2016/04/06 22:35:21
Oops. Removed.
| |
| 10 #include "base/mac/foundation_util.h" | 13 #include "base/mac/foundation_util.h" |
| 11 #include "base/strings/stringize_macros.h" | 14 #include "base/strings/stringize_macros.h" |
| 12 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 13 #include "base/trace_event/memory_allocator_dump.h" | 16 #include "base/trace_event/memory_allocator_dump.h" |
| 14 #include "base/trace_event/memory_dump_manager.h" | 17 #include "base/trace_event/memory_dump_manager.h" |
| 15 #include "base/trace_event/process_memory_dump.h" | 18 #include "base/trace_event/process_memory_dump.h" |
| 16 #include "ui/gl/gl_bindings.h" | 19 #include "ui/gl/gl_bindings.h" |
| 17 #include "ui/gl/gl_context.h" | 20 #include "ui/gl/gl_context.h" |
| 18 #include "ui/gl/gl_helper.h" | 21 #include "ui/gl/gl_helper.h" |
| 19 #include "ui/gl/scoped_binders.h" | 22 #include "ui/gl/scoped_binders.h" |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 NOTREACHED(); | 185 NOTREACHED(); |
| 183 return 0; | 186 return 0; |
| 184 } | 187 } |
| 185 | 188 |
| 186 NOTREACHED(); | 189 NOTREACHED(); |
| 187 return 0; | 190 return 0; |
| 188 } | 191 } |
| 189 | 192 |
| 190 } // namespace | 193 } // namespace |
| 191 | 194 |
| 195 // TODO(ccameron): Share this across all GLImages that share the same context. | |
| 196 class GLImageIOSurface::RGBConverter { | |
|
Daniele Castagna
2016/04/06 20:36:58
In my original patch I had a similar struct to kee
| |
| 197 public: | |
| 198 RGBConverter(); | |
| 199 ~RGBConverter() {} | |
| 200 bool CopyTexImage(IOSurfaceRef io_surface, const gfx::Size& size); | |
| 201 void DestroyGLResources(); | |
| 202 | |
| 203 private: | |
| 204 unsigned vertex_shader_ = 0; | |
| 205 unsigned fragment_shader_ = 0; | |
| 206 unsigned program_ = 0; | |
| 207 int size_location_ = -1; | |
| 208 unsigned vertex_buffer_ = 0; | |
| 209 | |
| 210 DISALLOW_COPY_AND_ASSIGN(RGBConverter); | |
| 211 }; | |
| 212 | |
| 192 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size, | 213 GLImageIOSurface::GLImageIOSurface(const gfx::Size& size, |
| 193 unsigned internalformat) | 214 unsigned internalformat) |
| 194 : size_(size), | 215 : size_(size), |
| 195 internalformat_(internalformat), | 216 internalformat_(internalformat), |
| 196 format_(BufferFormat::RGBA_8888) {} | 217 format_(BufferFormat::RGBA_8888) {} |
| 197 | 218 |
| 198 GLImageIOSurface::~GLImageIOSurface() { | 219 GLImageIOSurface::~GLImageIOSurface() { |
| 199 DCHECK(thread_checker_.CalledOnValidThread()); | 220 DCHECK(thread_checker_.CalledOnValidThread()); |
| 200 DCHECK(!io_surface_); | 221 DCHECK(!io_surface_); |
| 201 } | 222 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 232 return false; | 253 return false; |
| 233 } | 254 } |
| 234 | 255 |
| 235 if (!Initialize(io_surface, io_surface_id, format)) | 256 if (!Initialize(io_surface, io_surface_id, format)) |
| 236 return false; | 257 return false; |
| 237 | 258 |
| 238 cv_pixel_buffer_.reset(cv_pixel_buffer, base::scoped_policy::RETAIN); | 259 cv_pixel_buffer_.reset(cv_pixel_buffer, base::scoped_policy::RETAIN); |
| 239 return true; | 260 return true; |
| 240 } | 261 } |
| 241 | 262 |
| 263 void GLImageIOSurface::RGBConverter::DestroyGLResources() { | |
| 264 glDeleteProgram(program_); | |
| 265 glDeleteShader(vertex_shader_); | |
| 266 glDeleteShader(fragment_shader_); | |
| 267 glDeleteBuffersARB(1, &vertex_buffer_); | |
| 268 } | |
| 269 | |
| 242 void GLImageIOSurface::Destroy(bool have_context) { | 270 void GLImageIOSurface::Destroy(bool have_context) { |
| 243 DCHECK(thread_checker_.CalledOnValidThread()); | 271 DCHECK(thread_checker_.CalledOnValidThread()); |
| 244 if (have_context && framebuffer_) { | 272 if (have_context && rgb_converter_) |
| 245 glDeleteProgram(program_); | 273 rgb_converter_->DestroyGLResources(); |
| 246 glDeleteShader(vertex_shader_); | |
| 247 glDeleteShader(fragment_shader_); | |
| 248 glDeleteBuffersARB(1, &vertex_buffer_); | |
| 249 glDeleteFramebuffersEXT(1, &framebuffer_); | |
| 250 glDeleteTextures(2, yuv_textures_); | |
| 251 } | |
| 252 io_surface_.reset(); | 274 io_surface_.reset(); |
| 253 cv_pixel_buffer_.reset(); | 275 cv_pixel_buffer_.reset(); |
| 276 rgb_converter_.reset(); | |
| 254 } | 277 } |
| 255 | 278 |
| 256 gfx::Size GLImageIOSurface::GetSize() { | 279 gfx::Size GLImageIOSurface::GetSize() { |
| 257 return size_; | 280 return size_; |
| 258 } | 281 } |
| 259 | 282 |
| 260 unsigned GLImageIOSurface::GetInternalFormat() { | 283 unsigned GLImageIOSurface::GetInternalFormat() { |
| 261 return internalformat_; | 284 return internalformat_; |
| 262 } | 285 } |
| 263 | 286 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 bool GLImageIOSurface::CopyTexImage(unsigned target) { | 319 bool GLImageIOSurface::CopyTexImage(unsigned target) { |
| 297 DCHECK(thread_checker_.CalledOnValidThread()); | 320 DCHECK(thread_checker_.CalledOnValidThread()); |
| 298 | 321 |
| 299 if (format_ != BufferFormat::YUV_420_BIPLANAR) | 322 if (format_ != BufferFormat::YUV_420_BIPLANAR) |
| 300 return false; | 323 return false; |
| 301 if (target != GL_TEXTURE_RECTANGLE_ARB) { | 324 if (target != GL_TEXTURE_RECTANGLE_ARB) { |
| 302 LOG(ERROR) << "YUV_420_BIPLANAR requires GL_TEXTURE_RECTANGLE_ARB target"; | 325 LOG(ERROR) << "YUV_420_BIPLANAR requires GL_TEXTURE_RECTANGLE_ARB target"; |
| 303 return false; | 326 return false; |
| 304 } | 327 } |
| 305 | 328 |
| 306 if (!framebuffer_) { | 329 if (!rgb_converter_) |
| 307 glGenFramebuffersEXT(1, &framebuffer_); | 330 rgb_converter_.reset(new RGBConverter); |
| 308 vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); | 331 return rgb_converter_->CopyTexImage(io_surface_.get(), size_); |
| 309 vertex_shader_ = gfx::GLHelper::LoadShader( | 332 } |
| 310 GL_VERTEX_SHADER, | |
| 311 base::StringPrintf("%s\n%s", kGLSLVersion, kVertexShader).c_str()); | |
| 312 fragment_shader_ = gfx::GLHelper::LoadShader( | |
| 313 GL_FRAGMENT_SHADER, | |
| 314 base::StringPrintf("%s\n%s\n%s", kGLSLVersion, | |
| 315 kTextureRectangleRequired, kFragmentShader) | |
| 316 .c_str()); | |
| 317 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); | |
| 318 gfx::ScopedUseProgram use_program(program_); | |
| 319 | 333 |
| 320 size_location_ = glGetUniformLocation(program_, "a_texScale"); | 334 GLImageIOSurface::RGBConverter::RGBConverter() { |
| 321 DCHECK_NE(-1, size_location_); | 335 vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); |
| 322 int y_sampler_location = glGetUniformLocation(program_, "a_y_texture"); | 336 vertex_shader_ = gfx::GLHelper::LoadShader( |
| 323 DCHECK_NE(-1, y_sampler_location); | 337 GL_VERTEX_SHADER, |
| 324 int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture"); | 338 base::StringPrintf("%s\n%s", kGLSLVersion, kVertexShader).c_str()); |
| 325 DCHECK_NE(-1, uv_sampler_location); | 339 fragment_shader_ = gfx::GLHelper::LoadShader( |
| 340 GL_FRAGMENT_SHADER, | |
| 341 base::StringPrintf("%s\n%s\n%s", kGLSLVersion, kTextureRectangleRequired, | |
| 342 kFragmentShader) | |
| 343 .c_str()); | |
| 344 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); | |
| 345 gfx::ScopedUseProgram use_program(program_); | |
| 326 | 346 |
| 327 glUniform1i(y_sampler_location, 0); | 347 size_location_ = glGetUniformLocation(program_, "a_texScale"); |
| 328 glUniform1i(uv_sampler_location, 1); | 348 DCHECK_NE(-1, size_location_); |
| 349 int y_sampler_location = glGetUniformLocation(program_, "a_y_texture"); | |
| 350 DCHECK_NE(-1, y_sampler_location); | |
| 351 int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture"); | |
| 352 DCHECK_NE(-1, uv_sampler_location); | |
| 329 | 353 |
| 330 glGenTextures(2, yuv_textures_); | 354 glUniform1i(y_sampler_location, 0); |
| 331 DCHECK(yuv_textures_[0]); | 355 glUniform1i(uv_sampler_location, 1); |
| 332 DCHECK(yuv_textures_[1]); | 356 } |
| 333 } | |
| 334 | 357 |
| 358 bool GLImageIOSurface::RGBConverter::CopyTexImage(IOSurfaceRef io_surface, | |
| 359 const gfx::Size& size) { | |
| 335 CGLContextObj cgl_context = | 360 CGLContextObj cgl_context = |
| 336 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); | 361 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); |
| 337 | 362 |
| 338 GLint target_texture = 0; | 363 GLint target_texture = 0; |
| 339 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &target_texture); | 364 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &target_texture); |
| 340 DCHECK(target_texture); | 365 DCHECK(target_texture); |
| 341 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, size_.width(), | 366 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, size.width(), size.height(), |
| 342 size_.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); | 367 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); |
| 368 | |
| 369 // Ensure that all textures bound to IOSurfaces be destroyed before the | |
| 370 // function exits. If they are not destroyed they may cause deadlocks between | |
| 371 // VTDecompressionSession at CGLContextDestroy. | |
| 372 // https://crbug.com/598388 | |
| 373 unsigned y_texture = 0; | |
| 374 glGenTextures(1, &y_texture); | |
| 375 unsigned uv_texture = 0; | |
| 376 glGenTextures(1, &uv_texture); | |
| 377 unsigned framebuffer = 0; | |
| 378 glGenFramebuffersEXT(1, &framebuffer); | |
|
Daniele Castagna
2016/04/06 20:36:58
Do we need to regen this one all the time too?
ccameron
2016/04/06 22:35:21
It made the RGBConverter not capture any state of
| |
| 379 base::ScopedClosureRunner destroy_resources_runner(base::BindBlock(^{ | |
|
Daniele Castagna
2016/04/06 20:36:58
nit: I'm assuming the caret has some special meani
ccameron
2016/04/06 22:35:21
Yeah, it's for a block, which is the ObjC version
Daniele Castagna
2016/04/07 01:35:07
Can't you just add {y,uv}_texture in the closure l
ccameron
2016/04/07 07:10:34
If I include y/uv in the closure list, then I can'
| |
| 380 glDeleteTextures(1, &y_texture); | |
| 381 glDeleteTextures(1, &uv_texture); | |
| 382 glDeleteFramebuffersEXT(1, &framebuffer); | |
| 383 })); | |
| 343 | 384 |
| 344 CGLError cgl_error = kCGLNoError; | 385 CGLError cgl_error = kCGLNoError; |
| 345 { | 386 { |
| 346 DCHECK(io_surface_); | |
| 347 | |
| 348 gfx::ScopedActiveTexture active_texture0(GL_TEXTURE0); | 387 gfx::ScopedActiveTexture active_texture0(GL_TEXTURE0); |
| 349 gfx::ScopedTextureBinder texture_y_binder(GL_TEXTURE_RECTANGLE_ARB, | 388 gfx::ScopedTextureBinder texture_y_binder(GL_TEXTURE_RECTANGLE_ARB, |
| 350 yuv_textures_[0]); | 389 y_texture); |
| 351 cgl_error = CGLTexImageIOSurface2D( | 390 cgl_error = CGLTexImageIOSurface2D(cgl_context, GL_TEXTURE_RECTANGLE_ARB, |
| 352 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RED, size_.width(), | 391 GL_RED, size.width(), size.height(), |
| 353 size_.height(), GL_RED, GL_UNSIGNED_BYTE, io_surface_.get(), 0); | 392 GL_RED, GL_UNSIGNED_BYTE, io_surface, 0); |
| 354 if (cgl_error != kCGLNoError) { | 393 if (cgl_error != kCGLNoError) { |
| 355 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. " | 394 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. " |
| 356 << cgl_error; | 395 << cgl_error; |
| 357 return false; | 396 return false; |
| 358 } | 397 } |
| 359 { | 398 { |
| 360 gfx::ScopedActiveTexture active_texture1(GL_TEXTURE1); | 399 gfx::ScopedActiveTexture active_texture1(GL_TEXTURE1); |
| 361 gfx::ScopedTextureBinder texture_uv_binder(GL_TEXTURE_RECTANGLE_ARB, | 400 gfx::ScopedTextureBinder texture_uv_binder(GL_TEXTURE_RECTANGLE_ARB, |
| 362 yuv_textures_[1]); | 401 uv_texture); |
| 363 cgl_error = CGLTexImageIOSurface2D( | 402 cgl_error = CGLTexImageIOSurface2D( |
| 364 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2, | 403 cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size.width() / 2, |
| 365 size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_.get(), 1); | 404 size.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface, 1); |
| 366 if (cgl_error != kCGLNoError) { | 405 if (cgl_error != kCGLNoError) { |
| 367 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. " | 406 LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. " |
| 368 << cgl_error; | 407 << cgl_error; |
| 369 return false; | 408 return false; |
| 370 } | 409 } |
| 371 | 410 |
| 372 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); | 411 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer); |
| 373 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); | 412 gfx::ScopedViewport viewport(0, 0, size.width(), size.height()); |
| 374 glViewport(0, 0, size_.width(), size_.height()); | 413 glViewport(0, 0, size.width(), size.height()); |
| 375 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 414 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 376 GL_TEXTURE_RECTANGLE_ARB, target_texture, 0); | 415 GL_TEXTURE_RECTANGLE_ARB, target_texture, 0); |
| 377 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), | 416 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), |
| 378 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); | 417 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); |
| 379 | 418 |
| 380 gfx::ScopedUseProgram use_program(program_); | 419 gfx::ScopedUseProgram use_program(program_); |
| 381 glUniform2f(size_location_, size_.width(), size_.height()); | 420 glUniform2f(size_location_, size.width(), size.height()); |
| 382 | 421 |
| 383 gfx::GLHelper::DrawQuad(vertex_buffer_); | 422 gfx::GLHelper::DrawQuad(vertex_buffer_); |
| 384 // Detach the output texture from the fbo. | 423 // Detach the output texture from the fbo. |
| 385 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 424 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 386 GL_TEXTURE_RECTANGLE_ARB, 0, 0); | 425 GL_TEXTURE_RECTANGLE_ARB, 0, 0); |
| 387 } | 426 } |
| 388 } | 427 } |
| 389 return true; | 428 return true; |
| 390 } | 429 } |
| 391 | 430 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 440 g_widget_to_layer_map.Pointer()->erase(widget); | 479 g_widget_to_layer_map.Pointer()->erase(widget); |
| 441 } | 480 } |
| 442 | 481 |
| 443 // static | 482 // static |
| 444 unsigned GLImageIOSurface::GetInternalFormatForTesting( | 483 unsigned GLImageIOSurface::GetInternalFormatForTesting( |
| 445 gfx::BufferFormat format) { | 484 gfx::BufferFormat format) { |
| 446 DCHECK(ValidFormat(format)); | 485 DCHECK(ValidFormat(format)); |
| 447 return TextureFormat(format); | 486 return TextureFormat(format); |
| 448 } | 487 } |
| 449 } // namespace gl | 488 } // namespace gl |
| OLD | NEW |