Chromium Code Reviews| Index: gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc |
| 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 338772a23351f630855dd291b39525b7f0656d9b..ff4d62a5d1d52031eccca07a0a400868fa592042 100644 |
| --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc |
| +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc |
| @@ -617,6 +617,174 @@ void DoCopyTexSubImage2D(const gpu::gles2::GLES2Decoder* decoder, |
| decoder->RestoreFramebufferBindings(); |
| } |
| +// Convert RGBA/UNSIGNED_BYTE source to RGB/UNSIGNED_BYTE destination. |
| +void convertToRGB(const uint8_t* source, |
| + uint8_t* destination, |
| + unsigned length) { |
| + for (unsigned i = 0; i < length; ++i) { |
| + destination[0] = source[0]; |
| + destination[1] = source[1]; |
| + destination[2] = source[2]; |
| + source += 4; |
| + destination += 3; |
| + } |
| +} |
| + |
| +// Convert RGBA/UNSIGNED_BYTE source to RGB/FLOAT destination. |
| +void convertToRGBFloat(const uint8_t* source, |
| + float* destination, |
| + unsigned length) { |
| + const float scaleFactor = 1.0f / 255.0f; |
| + for (unsigned i = 0; i < length; ++i) { |
| + destination[0] = source[0] * scaleFactor; |
| + destination[1] = source[1] * scaleFactor; |
| + destination[2] = source[2] * scaleFactor; |
| + source += 4; |
| + destination += 3; |
| + } |
| +} |
| + |
| +void DoReadbackAndTexImage2D(const gpu::gles2::GLES2Decoder* decoder, |
| + GLenum source_target, |
| + GLuint source_id, |
| + GLint source_level, |
| + GLenum dest_target, |
| + GLuint dest_id, |
| + GLint dest_level, |
| + GLenum dest_internal_format, |
| + GLsizei width, |
| + GLsizei height, |
| + GLuint framebuffer) { |
| + DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), source_target); |
| + GLenum dest_binding_target = |
| + gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target); |
| + DCHECK(dest_binding_target == GL_TEXTURE_2D || |
| + dest_binding_target == GL_TEXTURE_CUBE_MAP); |
| + DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable()); |
| + if (BindFramebufferTexture2D(source_target, source_id, source_level, |
| + framebuffer)) { |
| + std::unique_ptr<uint8_t[]> buf(new uint8_t[width * height * 4]); |
| + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf.get()); |
|
Zhenyao Mo
2017/03/20 17:05:40
It would be really beneficial to explore the path
qiankun
2017/03/21 08:47:13
This is a good suggestion. Thanks! I did experimen
qiankun
2017/03/29 09:00:10
I did some experiments by running src/third_party/
|
| + glBindTexture(dest_binding_target, dest_id); |
| + glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| + glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| + glTexParameteri(dest_binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + GLenum format = GL_RGBA; |
| + GLenum type = GL_UNSIGNED_BYTE; |
| + switch (dest_internal_format) { |
| + case GL_RGB9_E5: { |
| + format = GL_RGB; |
| + type = GL_FLOAT; |
| + std::unique_ptr<float[]> data(new float[width * height * 3]); |
| + convertToRGBFloat(buf.get(), data.get(), width * height); |
| + glTexImage2D(dest_target, dest_level, dest_internal_format, width, |
| + height, 0, format, type, data.get()); |
| + break; |
| + } |
| + case GL_RGB5_A1: |
| + glTexImage2D(dest_target, dest_level, dest_internal_format, width, |
| + height, 0, format, type, buf.get()); |
| + break; |
| + case GL_SRGB_EXT: |
| + case GL_SRGB8: { |
| + format = GL_RGB; |
| + std::unique_ptr<uint8_t[]> data(new uint8_t[width * height * 3]); |
| + convertToRGB(buf.get(), data.get(), width * height); |
| + glTexImage2D(dest_target, dest_level, dest_internal_format, width, |
| + height, 0, format, type, data.get()); |
| + break; |
| + } |
| + case GL_SRGB_ALPHA_EXT: |
| + case GL_SRGB8_ALPHA8: |
| + glTexImage2D(dest_target, dest_level, dest_internal_format, width, |
| + height, 0, format, type, buf.get()); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + } |
| + |
| + decoder->RestoreTextureState(source_id); |
| + decoder->RestoreTextureState(dest_id); |
| + decoder->RestoreTextureUnitBindings(0); |
| + decoder->RestoreActiveTexture(); |
| + decoder->RestoreFramebufferBindings(); |
| +} |
| + |
| +void DoReadbackAndTexSubImage2D(const gpu::gles2::GLES2Decoder* decoder, |
| + GLenum source_target, |
| + GLuint source_id, |
| + GLint source_level, |
| + GLenum dest_target, |
| + GLuint dest_id, |
| + GLint dest_level, |
| + GLenum dest_internal_format, |
| + GLint xoffset, |
| + GLint yoffset, |
| + GLsizei width, |
| + GLsizei height, |
| + GLuint framebuffer) { |
| + DCHECK(source_target == GL_TEXTURE_2D || |
| + source_target == GL_TEXTURE_RECTANGLE_ARB); |
| + GLenum dest_binding_target = |
| + gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target); |
| + DCHECK(dest_binding_target == GL_TEXTURE_2D || |
| + dest_binding_target == GL_TEXTURE_CUBE_MAP); |
| + DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable()); |
| + if (BindFramebufferTexture2D(source_target, source_id, source_level, |
| + framebuffer)) { |
| + std::unique_ptr<uint8_t[]> buf(new uint8_t[width * height * 4]); |
| + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf.get()); |
| + glBindTexture(dest_binding_target, dest_id); |
| + glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| + glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| + glTexParameteri(dest_binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + GLenum format = GL_RGBA; |
| + GLenum type = GL_UNSIGNED_BYTE; |
| + switch (dest_internal_format) { |
| + case GL_RGB9_E5: { |
| + format = GL_RGB; |
| + type = GL_FLOAT; |
| + std::unique_ptr<float[]> data(new float[width * height * 3]); |
| + convertToRGBFloat(buf.get(), data.get(), width * height); |
| + glTexSubImage2D(dest_target, dest_level, xoffset, yoffset, width, |
| + height, format, type, data.get()); |
| + break; |
| + } |
| + case GL_RGB5_A1: |
| + glTexSubImage2D(dest_target, dest_level, xoffset, yoffset, width, |
| + height, format, type, buf.get()); |
| + break; |
| + case GL_SRGB_EXT: |
| + case GL_SRGB8: { |
| + format = GL_RGB; |
| + std::unique_ptr<uint8_t[]> data(new uint8_t[width * height * 3]); |
| + convertToRGB(buf.get(), data.get(), width * height); |
| + glTexSubImage2D(dest_target, dest_level, xoffset, yoffset, width, |
| + height, format, type, data.get()); |
| + break; |
| + } |
| + case GL_SRGB_ALPHA_EXT: |
| + case GL_SRGB8_ALPHA8: |
| + glTexSubImage2D(dest_target, dest_level, xoffset, yoffset, width, |
| + height, format, type, buf.get()); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + } |
| + |
| + decoder->RestoreTextureState(source_id); |
| + decoder->RestoreTextureState(dest_id); |
| + decoder->RestoreTextureUnitBindings(0); |
| + decoder->RestoreActiveTexture(); |
| + decoder->RestoreFramebufferBindings(); |
| +} |
| + |
| } // namespace |
| namespace gpu { |
| @@ -735,9 +903,11 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTexture( |
| GLint original_dest_level = dest_level; |
| GLenum original_dest_target = dest_target; |
| GLenum original_internal_format = dest_internal_format; |
| - if (method == DRAW_AND_COPY) { |
| + if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) { |
| GLenum adjusted_internal_format = |
| - getIntermediateFormat(dest_internal_format); |
| + method == DRAW_AND_READBACK |
| + ? GL_RGBA |
| + : getIntermediateFormat(dest_internal_format); |
| dest_target = GL_TEXTURE_2D; |
| glGenTextures(1, &intermediate_texture); |
| glBindTexture(dest_target, intermediate_texture); |
| @@ -758,11 +928,18 @@ void CopyTextureCHROMIUMResourceManager::DoCopyTexture( |
| dest_target, dest_texture, dest_level, dest_internal_format, width, |
| height, flip_y, premultiply_alpha, unpremultiply_alpha, kIdentityMatrix); |
| - if (method == DRAW_AND_COPY) { |
| + if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) { |
| source_level = 0; |
| - DoCopyTexImage2D(decoder, dest_target, intermediate_texture, source_level, |
| - original_dest_target, dest_id, original_dest_level, |
| - original_internal_format, width, height, framebuffer_); |
| + if (method == DRAW_AND_COPY) { |
| + DoCopyTexImage2D(decoder, dest_target, intermediate_texture, source_level, |
| + original_dest_target, dest_id, original_dest_level, |
| + original_internal_format, width, height, framebuffer_); |
| + } else if (method == DRAW_AND_READBACK) { |
| + DoReadbackAndTexImage2D(decoder, dest_target, intermediate_texture, |
| + source_level, original_dest_target, dest_id, |
| + original_dest_level, original_internal_format, |
| + width, height, framebuffer_); |
| + } |
| glDeleteTextures(1, &intermediate_texture); |
| } |
| } |
| @@ -805,9 +982,12 @@ void CopyTextureCHROMIUMResourceManager::DoCopySubTexture( |
| GLint original_dest_level = dest_level; |
| GLenum original_dest_target = dest_target; |
| GLuint intermediate_texture = 0; |
| - if (method == DRAW_AND_COPY) { |
| + GLenum original_internal_format = dest_internal_format; |
| + if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) { |
| GLenum adjusted_internal_format = |
| - getIntermediateFormat(dest_internal_format); |
| + method == DRAW_AND_READBACK |
| + ? GL_RGBA |
| + : getIntermediateFormat(dest_internal_format); |
| dest_target = GL_TEXTURE_2D; |
| glGenTextures(1, &intermediate_texture); |
| glBindTexture(dest_target, intermediate_texture); |
| @@ -834,12 +1014,19 @@ void CopyTextureCHROMIUMResourceManager::DoCopySubTexture( |
| source_height, flip_y, premultiply_alpha, unpremultiply_alpha, |
| kIdentityMatrix); |
| - if (method == DRAW_AND_COPY) { |
| + if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) { |
| source_level = 0; |
| - DoCopyTexSubImage2D(decoder, dest_target, intermediate_texture, |
| - source_level, original_dest_target, dest_id, |
| - original_dest_level, xoffset, yoffset, 0, 0, width, |
| - height, framebuffer_); |
| + if (method == DRAW_AND_COPY) { |
| + DoCopyTexSubImage2D(decoder, dest_target, intermediate_texture, |
| + source_level, original_dest_target, dest_id, |
| + original_dest_level, xoffset, yoffset, 0, 0, width, |
| + height, framebuffer_); |
| + } else if (method == DRAW_AND_READBACK) { |
| + DoReadbackAndTexSubImage2D(decoder, dest_target, intermediate_texture, |
| + source_level, original_dest_target, dest_id, |
| + original_dest_level, original_internal_format, |
| + xoffset, yoffset, width, height, framebuffer_); |
| + } |
| glDeleteTextures(1, &intermediate_texture); |
| } |
| } |