| 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..d59fc1c05e2f23237cf35c8cbd8918a334881bb8 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,172 @@ 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 pixelsPerRow) {
|
| + for (unsigned i = 0; i < pixelsPerRow; ++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 pixelsPerRow) {
|
| + const float scaleFactor = 1.0f / 255.0f;
|
| + for (unsigned i = 0; i < pixelsPerRow; ++i) {
|
| + destination[0] = source[0] * scaleFactor;
|
| + destination[1] = source[1] * scaleFactor;
|
| + destination[2] = source[2] * scaleFactor;
|
| + source += 4;
|
| + destination += 3;
|
| + }
|
| +}
|
| +
|
| +// Prepare the image data to be uploaded to a texture in pixel unpack buffer.
|
| +void prepareUnpackBuffer(GLuint buffer[2],
|
| + bool is_es,
|
| + GLenum format,
|
| + GLenum type,
|
| + GLsizei width,
|
| + GLsizei height) {
|
| + uint32_t pixel_num = width * height;
|
| + glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer[0]);
|
| +
|
| + // Result of glReadPixels with format == GL_RGB and type == GL_UNSIGNED_BYTE
|
| + // from read framebuffer in RGBA fromat is not correct on desktop core
|
| + // profile on both Linux Mesa and Linux NVIDIA. This may be a driver bug.
|
| + bool is_rgb_unsigned_byte = format == GL_RGB && type == GL_UNSIGNED_BYTE;
|
| + if ((!is_es && !is_rgb_unsigned_byte) ||
|
| + (format == GL_RGBA && type == GL_UNSIGNED_BYTE)) {
|
| + uint32_t bytes_per_group =
|
| + gpu::gles2::GLES2Util::ComputeImageGroupSize(format, type);
|
| + glBufferData(GL_PIXEL_PACK_BUFFER, pixel_num * bytes_per_group, 0,
|
| + GL_STATIC_READ);
|
| + glReadPixels(0, 0, width, height, format, type, 0);
|
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[0]);
|
| + return;
|
| + }
|
| +
|
| + uint32_t bytes_per_group =
|
| + gpu::gles2::GLES2Util::ComputeImageGroupSize(GL_RGBA, GL_UNSIGNED_BYTE);
|
| + uint32_t buf_size = pixel_num * bytes_per_group;
|
| +
|
| + if (format == GL_RGB && type == GL_FLOAT) {
|
| + glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, 0, GL_STATIC_READ);
|
| + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
| + void* pixels =
|
| + glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, buf_size, GL_MAP_READ_BIT);
|
| +
|
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[1]);
|
| + bytes_per_group =
|
| + gpu::gles2::GLES2Util::ComputeImageGroupSize(format, type);
|
| + buf_size = pixel_num * bytes_per_group;
|
| + glBufferData(GL_PIXEL_UNPACK_BUFFER, buf_size, 0, GL_STATIC_DRAW);
|
| + void* data =
|
| + glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buf_size, GL_MAP_WRITE_BIT);
|
| + convertToRGBFloat((uint8_t*)pixels, (float*)data, pixel_num);
|
| + glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
| + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
| + return;
|
| + }
|
| +
|
| + if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
|
| + glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, 0, GL_DYNAMIC_DRAW);
|
| + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
| + void* pixels = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, buf_size,
|
| + GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
|
| + void* data = pixels;
|
| + convertToRGB((uint8_t*)pixels, (uint8_t*)data, pixel_num);
|
| + glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[0]);
|
| + return;
|
| + }
|
| +
|
| + NOTREACHED();
|
| +}
|
| +
|
| +void DoReadbackAndTexImage(bool is_tex_image,
|
| + 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_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)) {
|
| + 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;
|
| + break;
|
| + case GL_SRGB_EXT:
|
| + case GL_SRGB8:
|
| + format = GL_RGB;
|
| + break;
|
| + case GL_RGB5_A1:
|
| + case GL_SRGB_ALPHA_EXT:
|
| + case GL_SRGB8_ALPHA8:
|
| + break;
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +
|
| + // TODO(qiankun.miao@intel.com): PIXEL_PACK_BUFFER and PIXEL_UNPACK_BUFFER
|
| + // are not supported in ES2.
|
| + bool is_es = decoder->GetFeatureInfo()->gl_version_info().is_es;
|
| + DCHECK(!is_es || decoder->GetFeatureInfo()->gl_version_info().is_es3);
|
| +
|
| + uint32_t buffer_num = is_es && format == GL_RGB && type == GL_FLOAT ? 2 : 1;
|
| + GLuint buffer[2];
|
| + glGenBuffersARB(buffer_num, buffer);
|
| + prepareUnpackBuffer(buffer, is_es, format, type, width, height);
|
| +
|
| + if (is_tex_image) {
|
| + glTexImage2D(dest_target, dest_level, dest_internal_format, width, height,
|
| + 0, format, type, 0);
|
| + } else {
|
| + glTexSubImage2D(dest_target, dest_level, xoffset, yoffset, width, height,
|
| + format, type, 0);
|
| + }
|
| + glDeleteBuffersARB(buffer_num, buffer);
|
| + }
|
| +
|
| + decoder->RestoreTextureState(source_id);
|
| + decoder->RestoreTextureState(dest_id);
|
| + decoder->RestoreTextureUnitBindings(0);
|
| + decoder->RestoreActiveTexture();
|
| + decoder->RestoreFramebufferBindings();
|
| + decoder->RestoreBufferBindings();
|
| +}
|
| +
|
| } // namespace
|
|
|
| namespace gpu {
|
| @@ -735,9 +901,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 +926,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) {
|
| + DoReadbackAndTexImage(true, decoder, dest_target, intermediate_texture,
|
| + source_level, original_dest_target, dest_id,
|
| + original_dest_level, original_internal_format, 0, 0,
|
| + width, height, framebuffer_);
|
| + }
|
| glDeleteTextures(1, &intermediate_texture);
|
| }
|
| }
|
| @@ -805,9 +980,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 +1012,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) {
|
| + DoReadbackAndTexImage(false, 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);
|
| }
|
| }
|
|
|