Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1459)

Unified Diff: gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc

Issue 2760843002: Add readback path for CopyTextureCHROMIUM (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
}
}

Powered by Google App Engine
This is Rietveld 408576698