123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/gl/yuv_to_rgb_converter.h"
- #include "base/notreached.h"
- #include "base/strings/stringize_macros.h"
- #include "base/strings/stringprintf.h"
- #include "ui/gfx/color_transform.h"
- #include "ui/gl/gl_helper.h"
- #include "ui/gl/gl_utils.h"
- #include "ui/gl/gl_version_info.h"
- #include "ui/gl/scoped_binders.h"
- namespace gl {
- namespace {
- const char kVertexHeaderES2[] =
- "precision mediump float;\n"
- "#define ATTRIBUTE attribute\n"
- "#define VARYING varying\n";
- const char kVertexHeaderES3[] =
- "#version 300 es\n"
- "precision mediump float;\n"
- "#define ATTRIBUTE in\n"
- "#define VARYING out\n";
- const char kVertexHeaderCompatiblityProfile[] =
- "#version 110\n"
- "#define ATTRIBUTE attribute\n"
- "#define VARYING varying\n";
- const char kVertexHeaderCoreProfile[] =
- "#version 150\n"
- "#define ATTRIBUTE in\n"
- "#define VARYING out\n";
- const char kFragmentHeaderES22D[] =
- "precision mediump float;\n"
- "#define VARYING varying\n"
- "#define FRAGCOLOR gl_FragColor\n"
- "#define TEX texture2D\n";
- const char kFragmentHeaderES2Rect[] =
- "#extension GL_ARB_texture_rectangle : require\n"
- "precision mediump float;\n"
- "#define VARYING varying\n"
- "#define FRAGCOLOR gl_FragColor\n"
- "#define TEX texture2DRect\n";
- const char kFragmentHeaderES3[] =
- "#version 300 es\n"
- "precision mediump float;\n"
- "#define VARYING in\n"
- "#define TEX texture\n"
- "#define FRAGCOLOR frag_color\n"
- "out vec4 FRAGCOLOR;\n";
- const char kFragmentHeaderCompatiblityProfile2D[] =
- "#version 110\n"
- "#define VARYING varying\n"
- "#define FRAGCOLOR gl_FragColor\n"
- "#define TEX texture2D\n";
- const char kFragmentHeaderCompatiblityProfileRect[] =
- "#version 110\n"
- "#extension GL_ARB_texture_rectangle : require\n"
- "#define VARYING varying\n"
- "#define FRAGCOLOR gl_FragColor\n"
- "#define TEX texture2DRect\n";
- const char kFragmentHeaderCoreProfile[] =
- "#version 150\n"
- "#define VARYING in\n"
- "#define TEX texture\n"
- "#define FRAGCOLOR frag_color\n"
- "out vec4 FRAGCOLOR;\n";
- // 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, 0.0, 1.0);
- v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5 * a_texScale;
- }
- );
- const char kFragmentShader2D[] =
- STRINGIZE(
- uniform sampler2D a_y_texture;
- uniform sampler2D a_uv_texture;
- VARYING vec2 v_texCoord;
- void main() {
- vec3 yuv = vec3(
- TEX(a_y_texture, v_texCoord).r,
- TEX(a_uv_texture, v_texCoord).rg);
- FRAGCOLOR = vec4(DoColorConversion(yuv), 1.0);
- }
- );
- const char kFragmentShaderRect[] =
- STRINGIZE(
- uniform sampler2DRect a_y_texture;
- uniform sampler2DRect a_uv_texture;
- VARYING vec2 v_texCoord;
- void main() {
- vec3 yuv = vec3(
- TEX(a_y_texture, v_texCoord).r,
- TEX(a_uv_texture, v_texCoord * 0.5).rg);
- FRAGCOLOR = vec4(DoColorConversion(yuv), 1.0);
- }
- );
- // clang-format on
- } // namespace
- YUVToRGBConverter::YUVToRGBConverter(const GLVersionInfo& gl_version_info,
- const gfx::ColorSpace& color_space) {
- std::unique_ptr<gfx::ColorTransform> color_transform =
- gfx::ColorTransform::NewColorTransform(color_space,
- color_space.GetAsFullRangeRGB());
- std::string do_color_conversion = color_transform->GetShaderSource();
- // On MacOS, the default texture target for native GpuMemoryBuffers is
- // GL_TEXTURE_RECTANGLE_ARB. This is due to CGL's requirements for creating
- // a GL surface. However, when ANGLE is used on top of SwiftShader or Metal,
- // it's necessary to use GL_TEXTURE_2D instead.
- // TODO(crbug.com/1056312): The proper behavior is to check the config
- // parameter set by the EGL_ANGLE_iosurface_client_buffer extension
- bool is_rect =
- !gl_version_info.is_angle_swiftshader && !gl_version_info.is_angle_metal;
- source_texture_target_ = (is_rect ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D);
- const char* fragment_header = nullptr;
- const char* vertex_header = nullptr;
- if (gl_version_info.is_es2) {
- vertex_header = kVertexHeaderES2;
- fragment_header = (is_rect ? kFragmentHeaderES2Rect : kFragmentHeaderES22D);
- } else if (gl_version_info.is_es3) {
- vertex_header = kVertexHeaderES3;
- fragment_header = kFragmentHeaderES3;
- } else if (gl_version_info.is_desktop_core_profile) {
- vertex_header = kVertexHeaderCoreProfile;
- fragment_header = kFragmentHeaderCoreProfile;
- } else {
- DCHECK(!gl_version_info.is_es);
- vertex_header = kVertexHeaderCompatiblityProfile;
- fragment_header = (is_rect ? kFragmentHeaderCompatiblityProfileRect
- : kFragmentHeaderCompatiblityProfile2D);
- }
- DCHECK(vertex_header && fragment_header);
- glGenFramebuffersEXT(1, &framebuffer_);
- {
- // In contexts that are in WebGL compatibility mode, we need to temporarily
- // enable GL_ANGLE_TEXTURE_RECTANGLE in order to compile the fragment
- // shader. Furthermore, in ES2 contexts, the GL_ANGLE_webgl_compatibility
- // extension is required for using GL_ANGLE_TEXTURE_RECTANGLE as an argument
- // to glEnable/Disable. Therefore the GL_ANGLE_webgl_compatibility
- // extension is a necessary and sufficient condition for determining whether
- // GL_ANGLE_TEXTURE_RECTANGLE needs to be temporarily enabled.
- ScopedEnableTextureRectangleInShaderCompiler enable(
- (is_rect && g_current_gl_driver->ext.b_GL_ANGLE_webgl_compatibility)
- ? g_current_gl_context
- : nullptr);
- vertex_buffer_ = GLHelper::SetupQuadVertexBuffer();
- vertex_shader_ = GLHelper::LoadShader(
- GL_VERTEX_SHADER,
- base::StringPrintf("%s\n%s", vertex_header, kVertexShader).c_str());
- fragment_shader_ = GLHelper::LoadShader(
- GL_FRAGMENT_SHADER,
- base::StringPrintf("%s\n%s\n%s", fragment_header,
- do_color_conversion.c_str(),
- (is_rect ? kFragmentShaderRect : kFragmentShader2D))
- .c_str());
- program_ = GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
- }
- 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);
- glGenTextures(1, &y_texture_);
- glGenTextures(1, &uv_texture_);
- glUniform1i(y_sampler_location, 0);
- glUniform1i(uv_sampler_location, 1);
- bool has_vertex_array_objects =
- gl_version_info.is_es3 || gl_version_info.is_desktop_core_profile;
- if (has_vertex_array_objects) {
- glGenVertexArraysOES(1, &vertex_array_object_);
- }
- has_get_tex_level_parameter_ =
- !gl_version_info.is_es || gl_version_info.IsAtLeastGLES(3, 1) ||
- g_current_gl_driver->ext.b_GL_ANGLE_get_tex_level_parameter;
- has_robust_resource_init_ =
- g_current_gl_driver->ext.b_GL_ANGLE_robust_resource_initialization;
- has_sampler_objects_ = gl_version_info.IsAtLeastGLES(3, 0) ||
- gl_version_info.IsAtLeastGL(3, 3) ||
- g_current_gl_driver->ext.b_GL_ARB_sampler_objects;
- }
- YUVToRGBConverter::~YUVToRGBConverter() {
- glDeleteTextures(1, &y_texture_);
- glDeleteTextures(1, &uv_texture_);
- glDeleteProgram(program_);
- glDeleteShader(vertex_shader_);
- glDeleteShader(fragment_shader_);
- glDeleteBuffersARB(1, &vertex_buffer_);
- glDeleteFramebuffersEXT(1, &framebuffer_);
- if (vertex_array_object_) {
- glDeleteVertexArraysOES(1, &vertex_array_object_);
- }
- }
- void YUVToRGBConverter::CopyYUV420ToRGB(unsigned target,
- const gfx::Size& size,
- unsigned rgb_texture,
- unsigned rgb_texture_type) {
- GLenum source_target_getter = 0;
- switch (source_texture_target_) {
- case GL_TEXTURE_2D:
- source_target_getter = GL_TEXTURE_BINDING_2D;
- break;
- case GL_TEXTURE_RECTANGLE_ARB:
- source_target_getter = GL_TEXTURE_BINDING_RECTANGLE_ARB;
- break;
- default:
- NOTIMPLEMENTED() << " Target not supported.";
- return;
- }
- // Note that state restoration is done explicitly 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(source_target_getter, &old_texture0_binding);
- GLint old_sampler0_binding = -1;
- if (has_sampler_objects_) {
- glGetIntegerv(GL_SAMPLER_BINDING, &old_sampler0_binding);
- glBindSampler(0, 0);
- }
- GLint old_texture1_binding = -1;
- glActiveTexture(GL_TEXTURE1);
- glGetIntegerv(source_target_getter, &old_texture1_binding);
- GLint old_sampler1_binding = -1;
- if (has_sampler_objects_) {
- glGetIntegerv(GL_SAMPLER_BINDING, &old_sampler1_binding);
- glBindSampler(1, 0);
- }
- // Allocate the rgb texture.
- glActiveTexture(old_active_texture);
- glBindTexture(target, rgb_texture);
- bool needs_texture_init = true;
- if (has_get_tex_level_parameter_) {
- GLint current_internal_format = 0;
- glGetTexLevelParameteriv(target, 0, GL_TEXTURE_INTERNAL_FORMAT,
- ¤t_internal_format);
- GLint current_type = 0;
- glGetTexLevelParameteriv(target, 0, GL_TEXTURE_RED_TYPE, ¤t_type);
- GLint current_width = 0;
- glGetTexLevelParameteriv(target, 0, GL_TEXTURE_WIDTH, ¤t_width);
- GLint current_height = 0;
- glGetTexLevelParameteriv(target, 0, GL_TEXTURE_HEIGHT, ¤t_height);
- if (current_internal_format == GL_RGBA &&
- static_cast<unsigned>(current_type) == rgb_texture_type &&
- current_width == size.width() && current_height == size.height()) {
- needs_texture_init = false;
- }
- }
- if (needs_texture_init) {
- glTexImage2D(target, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA,
- rgb_texture_type, nullptr);
- if (has_robust_resource_init_) {
- // We're about to overwrite the whole texture with a draw, notify the
- // driver that it doesn't need to perform robust resource init.
- glTexParameteri(target, GL_RESOURCE_INITIALIZED_ANGLE, GL_TRUE);
- }
- }
- // Set up and issue the draw call.
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(source_texture_target_, y_texture_);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(source_texture_target_, uv_texture_);
- ScopedFramebufferBinder framebuffer_binder(framebuffer_);
- ScopedViewport viewport(0, 0, size.width(), size.height());
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- target, rgb_texture, 0);
- DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
- glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
- ScopedUseProgram use_program(program_);
- if (source_texture_target_ == GL_TEXTURE_RECTANGLE_ARB) {
- glUniform2f(size_location_, size.width(), size.height());
- } else {
- glUniform2f(size_location_, 1, 1);
- }
- // User code may have set up the other vertex attributes in the
- // context in unexpected ways, including setting vertex attribute
- // divisors which may otherwise cause GL_INVALID_OPERATION during
- // glDrawArrays. Avoid interference by binding our own VAO during
- // the draw call. crbug.com/930479
- GLint old_vertex_array_object_ = 0;
- if (vertex_array_object_) {
- glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vertex_array_object_);
- glBindVertexArrayOES(vertex_array_object_);
- }
- GLHelper::DrawQuad(vertex_buffer_);
- if (vertex_array_object_) {
- glBindVertexArrayOES(old_vertex_array_object_);
- }
- // Restore previous state.
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- target, 0, 0);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(source_texture_target_, old_texture0_binding);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(source_texture_target_, old_texture1_binding);
- glActiveTexture(old_active_texture);
- if (old_sampler0_binding > 0)
- glBindSampler(0, old_sampler0_binding);
- if (old_sampler1_binding > 0)
- glBindSampler(1, old_sampler1_binding);
- }
- } // namespace gl
|