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 |