diff options
Diffstat (limited to 'chromium/ui/gl/gl_image_io_surface.mm')
| -rw-r--r-- | chromium/ui/gl/gl_image_io_surface.mm | 254 |
1 files changed, 48 insertions, 206 deletions
diff --git a/chromium/ui/gl/gl_image_io_surface.mm b/chromium/ui/gl/gl_image_io_surface.mm index 5d78bc67af7..b7cd2b4517f 100644 --- a/chromium/ui/gl/gl_image_io_surface.mm +++ b/chromium/ui/gl/gl_image_io_surface.mm @@ -7,20 +7,16 @@ #include <map> #include "base/callback_helpers.h" -#include "base/lazy_instance.h" #include "base/mac/bind_objc_block.h" #include "base/mac/foundation_util.h" -#include "base/strings/stringize_macros.h" -#include "base/strings/stringprintf.h" #include "base/trace_event/memory_allocator_dump.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/process_memory_dump.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" -#include "ui/gl/gl_helper.h" #include "ui/gl/scoped_api.h" #include "ui/gl/scoped_binders.h" -#include "ui/gl/scoped_cgl.h" +#include "ui/gl/yuv_to_rgb_converter.h" // Note that this must be included after gl_bindings.h to avoid conflicts. #include <OpenGL/CGLIOSurface.h> @@ -32,41 +28,6 @@ using gfx::BufferFormat; namespace gl { namespace { -const char kGLSLVersion[] = "#version 110"; - -const char kTextureRectangleRequired[] = - "#extension GL_ARB_texture_rectangle : require"; - -// clang-format off -const char kVertexShader[] = -STRINGIZE( - attribute vec2 a_position; - uniform vec2 a_texScale; - varying vec2 v_texCoord; - void main() { - gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); - v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5 * a_texScale; - } -); - -const char kFragmentShader[] = -STRINGIZE( - uniform sampler2DRect a_y_texture; - uniform sampler2DRect a_uv_texture; - varying vec2 v_texCoord; - void main() { - vec3 yuv_adj = vec3(-0.0625, -0.5, -0.5); - mat3 yuv_matrix = mat3(vec3(1.164, 1.164, 1.164), - vec3(0.0, -.391, 2.018), - vec3(1.596, -.813, 0.0)); - vec3 yuv = vec3( - texture2DRect(a_y_texture, v_texCoord).r, - texture2DRect(a_uv_texture, v_texCoord * 0.5).rg); - gl_FragColor = vec4(yuv_matrix * (yuv + yuv_adj), 1.0); - } -); -// clang-format on - bool ValidInternalFormat(unsigned internalformat) { switch (internalformat) { case GL_RED: @@ -190,170 +151,6 @@ GLenum DataType(BufferFormat format) { } // namespace -class GLImageIOSurface::RGBConverter - : public base::RefCounted<GLImageIOSurface::RGBConverter> { - public: - static scoped_refptr<RGBConverter> GetForCurrentContext(); - bool CopyTexImage(IOSurfaceRef io_surface, const gfx::Size& size); - - private: - friend class base::RefCounted<RGBConverter>; - RGBConverter(CGLContextObj cgl_context); - ~RGBConverter(); - - unsigned framebuffer_ = 0; - unsigned vertex_shader_ = 0; - unsigned fragment_shader_ = 0; - unsigned program_ = 0; - int size_location_ = -1; - unsigned vertex_buffer_ = 0; - base::ScopedTypeRef<CGLContextObj> cgl_context_; - - static base::LazyInstance< - std::map<CGLContextObj, GLImageIOSurface::RGBConverter*>> - g_rgb_converters; - static base::LazyInstance<base::ThreadChecker> - g_rgb_converters_thread_checker; -}; - -base::LazyInstance<std::map<CGLContextObj, GLImageIOSurface::RGBConverter*>> - GLImageIOSurface::RGBConverter::g_rgb_converters; - -base::LazyInstance<base::ThreadChecker> - GLImageIOSurface::RGBConverter::g_rgb_converters_thread_checker; - -scoped_refptr<GLImageIOSurface::RGBConverter> -GLImageIOSurface::RGBConverter::GetForCurrentContext() { - CGLContextObj current_context = CGLGetCurrentContext(); - DCHECK(current_context); - DCHECK(g_rgb_converters_thread_checker.Get().CalledOnValidThread()); - auto found = g_rgb_converters.Get().find(current_context); - if (found != g_rgb_converters.Get().end()) - return make_scoped_refptr(found->second); - return make_scoped_refptr(new RGBConverter(current_context)); -} - -GLImageIOSurface::RGBConverter::RGBConverter(CGLContextObj cgl_context) - : cgl_context_(cgl_context, base::scoped_policy::RETAIN) { - gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; - glGenFramebuffersEXT(1, &framebuffer_); - vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); - vertex_shader_ = gfx::GLHelper::LoadShader( - GL_VERTEX_SHADER, - base::StringPrintf("%s\n%s", kGLSLVersion, kVertexShader).c_str()); - fragment_shader_ = gfx::GLHelper::LoadShader( - GL_FRAGMENT_SHADER, - base::StringPrintf("%s\n%s\n%s", kGLSLVersion, kTextureRectangleRequired, - kFragmentShader) - .c_str()); - program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); - - gfx::ScopedUseProgram use_program(program_); - size_location_ = glGetUniformLocation(program_, "a_texScale"); - DCHECK_NE(-1, size_location_); - int y_sampler_location = glGetUniformLocation(program_, "a_y_texture"); - DCHECK_NE(-1, y_sampler_location); - int uv_sampler_location = glGetUniformLocation(program_, "a_uv_texture"); - DCHECK_NE(-1, uv_sampler_location); - - glUniform1i(y_sampler_location, 0); - glUniform1i(uv_sampler_location, 1); - - DCHECK(g_rgb_converters_thread_checker.Get().CalledOnValidThread()); - DCHECK(g_rgb_converters.Get().find(cgl_context) == - g_rgb_converters.Get().end()); - g_rgb_converters.Get()[cgl_context] = this; -} - -GLImageIOSurface::RGBConverter::~RGBConverter() { - DCHECK(g_rgb_converters_thread_checker.Get().CalledOnValidThread()); - DCHECK(g_rgb_converters.Get()[cgl_context_] == this); - g_rgb_converters.Get().erase(cgl_context_.get()); - { - gfx::ScopedCGLSetCurrentContext(cgl_context_.get()); - gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; - glDeleteProgram(program_); - glDeleteShader(vertex_shader_); - glDeleteShader(fragment_shader_); - glDeleteBuffersARB(1, &vertex_buffer_); - glDeleteFramebuffersEXT(1, &framebuffer_); - } - cgl_context_.reset(); -} - -bool GLImageIOSurface::RGBConverter::CopyTexImage(IOSurfaceRef io_surface, - const gfx::Size& size) { - gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; - DCHECK_EQ(CGLGetCurrentContext(), cgl_context_.get()); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, size.width(), size.height(), - 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); - GLint target_texture = 0; - glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &target_texture); - DCHECK(target_texture); - - // Note that state restoration is done explicitly in the ScopedClosureRunner - // instead of scoped binders to avoid https://crbug.com/601729. - GLint old_active_texture = -1; - glGetIntegerv(GL_ACTIVE_TEXTURE, &old_active_texture); - GLint old_texture0_binding = -1; - glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_texture0_binding); - GLint old_texture1_binding = -1; - glActiveTexture(GL_TEXTURE1); - glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_texture1_binding); - - unsigned y_texture = 0; - glGenTextures(1, &y_texture); - unsigned uv_texture = 0; - glGenTextures(1, &uv_texture); - - base::ScopedClosureRunner destroy_resources_runner(base::BindBlock(^{ - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, old_texture0_binding); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, old_texture1_binding); - glActiveTexture(old_active_texture); - - glDeleteTextures(1, &y_texture); - glDeleteTextures(1, &uv_texture); - })); - - CGLError cgl_error = kCGLNoError; - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, y_texture); - cgl_error = CGLTexImageIOSurface2D(cgl_context_, GL_TEXTURE_RECTANGLE_ARB, - GL_RED, size.width(), size.height(), - GL_RED, GL_UNSIGNED_BYTE, io_surface, 0); - if (cgl_error != kCGLNoError) { - LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. " - << cgl_error; - return false; - } - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, uv_texture); - cgl_error = CGLTexImageIOSurface2D(cgl_context_, GL_TEXTURE_RECTANGLE_ARB, - GL_RG, size.width() / 2, size.height() / 2, - GL_RG, GL_UNSIGNED_BYTE, io_surface, 1); - if (cgl_error != kCGLNoError) { - LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. " - << cgl_error; - return false; - } - - gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); - gfx::ScopedViewport viewport(0, 0, size.width(), size.height()); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_RECTANGLE_ARB, target_texture, 0); - DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), - glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); - gfx::ScopedUseProgram use_program(program_); - glUniform2f(size_location_, size.width(), size.height()); - gfx::GLHelper::DrawQuad(vertex_buffer_); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_RECTANGLE_ARB, 0, 0); - return true; -} - GLImageIOSurface::GLImageIOSurface(const gfx::Size& size, unsigned internalformat) : size_(size), @@ -455,13 +252,58 @@ bool GLImageIOSurface::CopyTexImage(unsigned target) { if (format_ != BufferFormat::YUV_420_BIPLANAR) return false; + if (target != GL_TEXTURE_RECTANGLE_ARB) { LOG(ERROR) << "YUV_420_BIPLANAR requires GL_TEXTURE_RECTANGLE_ARB target"; return false; } - rgb_converter_ = RGBConverter::GetForCurrentContext(); - return rgb_converter_->CopyTexImage(io_surface_.get(), size_); + gfx::GLContext* gl_context = gfx::GLContext::GetCurrent(); + DCHECK(gl_context); + + gl::YUVToRGBConverter* yuv_to_rgb_converter = + gl_context->GetYUVToRGBConverter(); + DCHECK(yuv_to_rgb_converter); + + gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; + + // Note that state restoration is done explicitly instead of scoped binders to + // avoid https://crbug.com/601729. + GLint rgb_texture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &rgb_texture); + base::ScopedClosureRunner destroy_resources_runner(base::BindBlock(^{ + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, rgb_texture); + })); + + CGLContextObj cgl_context = CGLGetCurrentContext(); + { + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, yuv_to_rgb_converter->y_texture()); + CGLError cgl_error = CGLTexImageIOSurface2D( + cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RED, size_.width(), + size_.height(), GL_RED, GL_UNSIGNED_BYTE, io_surface_, 0); + if (cgl_error != kCGLNoError) { + LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the Y plane. " + << cgl_error; + return false; + } + } + { + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, yuv_to_rgb_converter->uv_texture()); + CGLError cgl_error = CGLTexImageIOSurface2D( + cgl_context, GL_TEXTURE_RECTANGLE_ARB, GL_RG, size_.width() / 2, + size_.height() / 2, GL_RG, GL_UNSIGNED_BYTE, io_surface_, 1); + if (cgl_error != kCGLNoError) { + LOG(ERROR) << "Error in CGLTexImageIOSurface2D for the UV plane. " + << cgl_error; + return false; + } + } + + yuv_to_rgb_converter->CopyYUV420ToRGB( + GL_TEXTURE_RECTANGLE_ARB, + size_, + rgb_texture); + return true; } bool GLImageIOSurface::CopyTexSubImage(unsigned target, |
