diff options
5 files changed, 208 insertions, 64 deletions
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc index f72e1b2..a9392de 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.cc +++ b/content/common/gpu/media/android_video_decode_accelerator.cc @@ -357,10 +357,23 @@ void AndroidVideoDecodeAccelerator::SendCurrentSurfaceToClient( // attached. // 2. SurfaceTexture requires us to apply a transform matrix when we show // the texture. - copier_->DoCopyTexture(gl_decoder_.get(), GL_TEXTURE_EXTERNAL_OES, - GL_TEXTURE_2D, surface_texture_id_, - picture_buffer_texture_id, 0, size_.width(), - size_.height(), false, false, false); + // TODO(hkuang): get the StreamTexture transform matrix in GPU process + // instead of using default matrix crbug.com/226218. + const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + copier_->DoCopyTextureWithTransform(gl_decoder_.get(), + GL_TEXTURE_EXTERNAL_OES, + surface_texture_id_, + picture_buffer_texture_id, + 0, + size_.width(), + size_.height(), + false, + false, + false, + default_matrix); base::MessageLoop::current()->PostTask( FROM_HERE, diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt index 4431e49..fdaa7d6 100644 --- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt @@ -47,7 +47,18 @@ New Procedures and Functions destination texture. The level parameter must be 0 at present. The internal format of the destination texture is converted to that - specified by <internal_format>. + specified by <internal_format>. Must be one of the following symbolic + constants: GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA + When <source_id> texture doens't contain a superset of the component + required by <internal_format>, fill the components by following rules. + + source format color components + ================================================= + GL_ALPHA (0, 0, 0, A) + GL_LUMINANCE (L, L, L, 1) + GL_LUMINANCE_ALPHA (L, L, L, A) + GL_RGB (R, G, B, 1) + GL_RGBA (R, G, B, A) The format type of the destination texture is converted to that specified by <dest_type>. diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc index bda65ac..f98ca2e 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc @@ -167,7 +167,7 @@ FragmentShaderId GetFragmentShaderId(bool premultiply_alpha, } NOTREACHED(); - return shader_ids[index][SAMPLER_2D]; + return shader_ids[0][SAMPLER_2D]; } void CompileShader(GLuint shader, const char* shader_source) { @@ -186,6 +186,68 @@ void DeleteShader(GLuint shader) { glDeleteShader(shader); } +bool BindFramebufferTexture2D(GLenum target, + GLuint texture_id, + GLint level, + GLuint framebuffer) { + DCHECK(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB); + glActiveTexture(GL_TEXTURE0); + glBindTexture(target, texture_id); + // NVidia drivers require texture settings to be a certain way + // or they won't report FRAMEBUFFER_COMPLETE. + glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); + glFramebufferTexture2DEXT( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, texture_id, level); + +#ifndef NDEBUG + GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); + if (GL_FRAMEBUFFER_COMPLETE != fb_status) { + DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer."; + return false; + } +#endif + return true; +} + +void DoCopyTexImage2D(const gpu::gles2::GLES2Decoder* decoder, + GLenum source_target, + GLuint source_id, + GLuint dest_id, + GLint dest_level, + GLenum dest_internal_format, + GLsizei width, + GLsizei height, + GLuint framebuffer) { + DCHECK(source_target == GL_TEXTURE_2D || + source_target == GL_TEXTURE_RECTANGLE_ARB); + if (BindFramebufferTexture2D( + source_target, source_id, 0 /* level */, framebuffer)) { + glBindTexture(GL_TEXTURE_2D, dest_id); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glCopyTexImage2D(GL_TEXTURE_2D, + dest_level, + dest_internal_format, + 0 /* x */, + 0 /* y */, + width, + height, + 0 /* border */); + } + + decoder->RestoreTextureState(source_id); + decoder->RestoreTextureState(dest_id); + decoder->RestoreTextureUnitBindings(0); + decoder->RestoreActiveTexture(); + decoder->RestoreFramebufferBindings(); +} + } // namespace namespace gpu { @@ -197,13 +259,19 @@ CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager() buffer_id_(0u), framebuffer_(0u) {} -CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() {} +CopyTextureCHROMIUMResourceManager::~CopyTextureCHROMIUMResourceManager() { + DCHECK(!buffer_id_); + DCHECK(!framebuffer_); +} void CopyTextureCHROMIUMResourceManager::Initialize( const gles2::GLES2Decoder* decoder) { COMPILE_ASSERT( kVertexPositionAttrib == 0u, Position_attribs_must_be_0); + DCHECK(!buffer_id_); + DCHECK(!framebuffer_); + DCHECK(programs_.empty()); // Initialize all of the GPU resources required to perform the copy. glGenBuffersARB(1, &buffer_id_); @@ -227,6 +295,7 @@ void CopyTextureCHROMIUMResourceManager::Destroy() { return; glDeleteFramebuffersEXT(1, &framebuffer_); + framebuffer_ = 0; std::for_each(vertex_shaders_.begin(), vertex_shaders_.end(), DeleteShader); std::for_each( @@ -239,37 +308,70 @@ void CopyTextureCHROMIUMResourceManager::Destroy() { } glDeleteBuffersARB(1, &buffer_id_); + buffer_id_ = 0; } void CopyTextureCHROMIUMResourceManager::DoCopyTexture( const gles2::GLES2Decoder* decoder, GLenum source_target, - GLenum dest_target, GLuint source_id, + GLenum source_internal_format, GLuint dest_id, - GLint level, + GLint dest_level, + GLenum dest_internal_format, GLsizei width, GLsizei height, bool flip_y, bool premultiply_alpha, bool unpremultiply_alpha) { + bool premultiply_alpha_change = premultiply_alpha ^ unpremultiply_alpha; + // GL_INVALID_OPERATION is generated if the currently bound framebuffer's + // format does not contain a superset of the components required by the base + // format of internalformat. + // https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml + bool source_format_contain_superset_of_dest_format = + source_internal_format == dest_internal_format || + (source_internal_format == GL_RGBA && dest_internal_format == GL_RGB); + // GL_TEXTURE_RECTANGLE_ARB on FBO is supported by OpenGL, not GLES2, + // so restrict this to GL_TEXTURE_2D. + if (source_target == GL_TEXTURE_2D && !flip_y && !premultiply_alpha_change && + source_format_contain_superset_of_dest_format) { + DoCopyTexImage2D(decoder, + source_target, + source_id, + dest_id, + dest_level, + dest_internal_format, + width, + height, + framebuffer_); + return; + } + // Use default transform matrix if no transform passed in. const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - DoCopyTextureWithTransform(decoder, source_target, dest_target, source_id, - dest_id, level, width, height, flip_y, premultiply_alpha, - unpremultiply_alpha, default_matrix); + DoCopyTextureWithTransform(decoder, + source_target, + source_id, + dest_id, + dest_level, + width, + height, + flip_y, + premultiply_alpha, + unpremultiply_alpha, + default_matrix); } void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform( const gles2::GLES2Decoder* decoder, GLenum source_target, - GLenum dest_target, GLuint source_id, GLuint dest_id, - GLint level, + GLint dest_level, GLsizei width, GLsizei height, bool flip_y, @@ -286,27 +388,27 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform( VertexShaderId vertex_shader_id = GetVertexShaderId(flip_y); DCHECK_LT(static_cast<size_t>(vertex_shader_id), vertex_shaders_.size()); - GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id]; - if (!*vertex_shader) { - *vertex_shader = glCreateShader(GL_VERTEX_SHADER); - CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]); - } - FragmentShaderId fragment_shader_id = GetFragmentShaderId( premultiply_alpha, unpremultiply_alpha, source_target); DCHECK_LT(static_cast<size_t>(fragment_shader_id), fragment_shaders_.size()); - GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id]; - if (!*fragment_shader) { - *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - CompileShader(*fragment_shader, fragment_shader_source[fragment_shader_id]); - } ProgramMapKey key(vertex_shader_id, fragment_shader_id); ProgramInfo* info = &programs_[key]; // Create program if necessary. if (!info->program) { info->program = glCreateProgram(); + GLuint* vertex_shader = &vertex_shaders_[vertex_shader_id]; + if (!*vertex_shader) { + *vertex_shader = glCreateShader(GL_VERTEX_SHADER); + CompileShader(*vertex_shader, vertex_shader_source[vertex_shader_id]); + } glAttachShader(info->program, *vertex_shader); + GLuint* fragment_shader = &fragment_shaders_[fragment_shader_id]; + if (!*fragment_shader) { + *fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + CompileShader(*fragment_shader, + fragment_shader_source[fragment_shader_id]); + } glAttachShader(info->program, *fragment_shader); glBindAttribLocation(info->program, kVertexPositionAttrib, "a_position"); glLinkProgram(info->program); @@ -337,25 +439,9 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform( glUniform2f(info->half_size_handle, width / 2.0f, height / 2.0f); else glUniform2f(info->half_size_handle, 0.5f, 0.5f); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, dest_id); - // NVidia drivers require texture settings to be a certain way - // or they won't report FRAMEBUFFER_COMPLETE. - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer_); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_target, - dest_id, level); -#ifndef NDEBUG - GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); - if (GL_FRAMEBUFFER_COMPLETE != fb_status) { - DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer."; - } else -#endif - { + if (BindFramebufferTexture2D( + GL_TEXTURE_2D, dest_id, dest_level, framebuffer_)) { decoder->ClearAllAttributes(); glEnableVertexAttribArray(kVertexPositionAttrib); diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h index 17290f8..083fc4c 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h @@ -20,7 +20,8 @@ class GLES2Decoder; // This class encapsulates the resources required to implement the // GL_CHROMIUM_copy_texture extension. The copy operation is performed -// via a blit to a framebuffer object. +// via glCopyTexImage2D() or a blit to a framebuffer object. +// The target of |dest_id| texture must be GL_TEXTURE_2D. class GPU_EXPORT CopyTextureCHROMIUMResourceManager { public: CopyTextureCHROMIUMResourceManager(); @@ -29,18 +30,29 @@ class GPU_EXPORT CopyTextureCHROMIUMResourceManager { void Initialize(const gles2::GLES2Decoder* decoder); void Destroy(); - void DoCopyTexture(const gles2::GLES2Decoder* decoder, GLenum source_target, - GLenum dest_target, GLuint source_id, GLuint dest_id, - GLint level, GLsizei width, GLsizei height, - bool flip_y, bool premultiply_alpha, + void DoCopyTexture(const gles2::GLES2Decoder* decoder, + GLenum source_target, + GLuint source_id, + GLenum source_internal_format, + GLuint dest_id, + GLint dest_level, + GLenum dest_internal_format, + GLsizei width, + GLsizei height, + bool flip_y, + bool premultiply_alpha, bool unpremultiply_alpha); // This will apply a transform on the source texture before copying to // destination texture. void DoCopyTextureWithTransform(const gles2::GLES2Decoder* decoder, - GLenum source_target, GLenum dest_target, - GLuint source_id, GLuint dest_id, GLint level, - GLsizei width, GLsizei height, bool flip_y, + GLenum source_target, + GLuint source_id, + GLuint dest_id, + GLint dest_level, + GLsizei width, + GLsizei height, + bool flip_y, bool premultiply_alpha, bool unpremultiply_alpha, const GLfloat transform_matrix[16]); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 418ca3a..0a7f822 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -10055,6 +10055,11 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( return; } + GLenum source_type = 0; + GLenum source_internal_format = 0; + source_texture->GetLevelType( + source_texture->target(), 0, &source_type, &source_internal_format); + GLenum dest_type_previous = dest_type; GLenum dest_internal_format = internal_format; bool dest_level_defined = dest_texture->GetLevelSize( @@ -10065,6 +10070,20 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( &dest_internal_format); } + // The destination format should be GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, + // or GL_LUMINANCE_ALPHA. + bool valid_dest_format = dest_internal_format >= GL_ALPHA && + dest_internal_format <= GL_LUMINANCE_ALPHA; + // The source format can be GL_BGRA_EXT. + bool valid_source_format = (source_internal_format >= GL_ALPHA && + source_internal_format <= GL_LUMINANCE_ALPHA) || + source_internal_format == GL_BGRA_EXT; + if (!valid_source_format || !valid_dest_format) { + LOCAL_SET_GL_ERROR( + GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "invalid internal format"); + return; + } + // Resize the destination texture to the dimensions of the source texture. if (!dest_level_defined || dest_width != source_width || dest_height != source_height || @@ -10105,25 +10124,28 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( copy_texture_CHROMIUM_->DoCopyTextureWithTransform( this, source_texture->target(), - dest_texture->target(), source_texture->service_id(), - dest_texture->service_id(), level, - source_width, source_height, + dest_texture->service_id(), + level, + source_width, + source_height, unpack_flip_y_, unpack_premultiply_alpha_, unpack_unpremultiply_alpha_, default_matrix); } else { - copy_texture_CHROMIUM_->DoCopyTexture( - this, - source_texture->target(), - dest_texture->target(), - source_texture->service_id(), - dest_texture->service_id(), level, - source_width, source_height, - unpack_flip_y_, - unpack_premultiply_alpha_, - unpack_unpremultiply_alpha_); + copy_texture_CHROMIUM_->DoCopyTexture(this, + source_texture->target(), + source_texture->service_id(), + source_internal_format, + dest_texture->service_id(), + level, + internal_format, + source_width, + source_height, + unpack_flip_y_, + unpack_premultiply_alpha_, + unpack_unpremultiply_alpha_); } DoDidUseTexImageIfNeeded(source_texture, source_texture->target()); |