Index: content/common/gpu/client/gl_helper.cc |
diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc |
index eac9e12ffec65c3e6a6855282b1e669baa85a24b..c84a392ad7ec21327428b28103b8b1db3d1f32b5 100644 |
--- a/content/common/gpu/client/gl_helper.cc |
+++ b/content/common/gpu/client/gl_helper.cc |
@@ -142,7 +142,7 @@ class GLHelper::CopyTextureToImpl |
const gfx::Rect& src_subrect, |
const gfx::Size& dst_size, |
unsigned char* out, |
- const SkColorType color_type, |
+ const SkColorType out_color_type, |
const base::Callback<void(bool)>& callback, |
GLHelper::ScalerQuality quality); |
@@ -325,6 +325,25 @@ class GLHelper::CopyTextureToImpl |
SkColorType color_type, |
GLHelper::ScalerQuality quality); |
+ // Converts each four consecutive pixels of the source texture into one pixel |
+ // in the result texture with each pixel channel representing the grayscale |
+ // color of one of the four original pixels: |
+ // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X1X2X3X4 |
+ // The resulting texture is still an RGBA texture (which is ~4 times narrower |
+ // than the original). If rendered directly, it wouldn't show anything useful, |
+ // but the data in it can be used to construct a grayscale image. |
+ // |encoded_texture_size| is the exact size of the resulting RGBA texture. It |
+ // is equal to src_size.width()/4 rounded upwards. Some channels in the last |
+ // pixel ((-src_size.width()) % 4) to be exact) are padding and don't contain |
+ // useful data. |
+ // If swizzle is set to true, the transformed pixels are reordered: |
+ // R1G1B1A1 R2G2B2A2 R3G3B3A3 R4G4B4A4 -> X3X2X1X4. |
+ GLuint EncodeTextureAsGrayscale(GLuint src_texture, |
+ const gfx::Size& src_size, |
+ gfx::Size* const encoded_texture_size, |
+ bool vertically_flip_texture, |
+ bool swizzle); |
+ |
static void nullcallback(bool success) {} |
void ReadbackDone(Request *request, int bytes_per_pixel); |
void FinishRequest(Request* request, bool result); |
@@ -333,6 +352,7 @@ class GLHelper::CopyTextureToImpl |
static const float kRGBtoYColorWeights[]; |
static const float kRGBtoUColorWeights[]; |
static const float kRGBtoVColorWeights[]; |
+ static const float kRGBtoGrayscaleColorWeights[]; |
GLES2Interface* gl_; |
gpu::ContextSupport* context_support_; |
@@ -404,6 +424,43 @@ GLuint GLHelper::CopyTextureToImpl::ScaleTexture( |
return dst_texture; |
} |
+GLuint GLHelper::CopyTextureToImpl::EncodeTextureAsGrayscale( |
+ GLuint src_texture, |
+ const gfx::Size& src_size, |
+ gfx::Size* const encoded_texture_size, |
+ bool vertically_flip_texture, |
+ bool swizzle) { |
+ GLuint dst_texture = 0u; |
+ gl_->GenTextures(1, &dst_texture); |
+ // The size of the encoded texture. |
+ *encoded_texture_size = |
+ gfx::Size((src_size.width() + 3) / 4, src_size.height()); |
+ { |
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture); |
+ gl_->TexImage2D(GL_TEXTURE_2D, |
+ 0, |
+ GL_RGBA, |
+ encoded_texture_size->width(), |
+ encoded_texture_size->height(), |
+ 0, |
+ GL_RGBA, |
+ GL_UNSIGNED_BYTE, |
+ NULL); |
+ } |
+ |
+ helper_->InitScalerImpl(); |
+ scoped_ptr<ScalerInterface> grayscale_scaler( |
+ helper_->scaler_impl_.get()->CreatePlanarScaler( |
+ src_size, |
+ gfx::Rect(0, 0, (src_size.width() + 3) & ~3, src_size.height()), |
+ *encoded_texture_size, |
+ vertically_flip_texture, |
+ swizzle, |
+ kRGBtoGrayscaleColorWeights)); |
+ grayscale_scaler->Scale(src_texture, dst_texture); |
+ return dst_texture; |
+} |
+ |
void GLHelper::CopyTextureToImpl::ReadbackAsync( |
const gfx::Size& dst_size, |
int32 bytes_per_row, |
@@ -443,33 +500,86 @@ void GLHelper::CopyTextureToImpl::ReadbackAsync( |
base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), |
request, bytes_per_pixel)); |
} |
+ |
void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( |
GLuint src_texture, |
const gfx::Size& src_size, |
const gfx::Rect& src_subrect, |
const gfx::Size& dst_size, |
unsigned char* out, |
- const SkColorType color_type, |
+ const SkColorType out_color_type, |
const base::Callback<void(bool)>& callback, |
GLHelper::ScalerQuality quality) { |
GLenum format, type; |
size_t bytes_per_pixel; |
- FormatSupport supported = |
- GetReadbackConfig(color_type, true, &format, &type, &bytes_per_pixel); |
+ SkColorType readback_color_type = out_color_type; |
+ // Single-component textures are not supported by all GPUs, so we implement |
+ // kAlpha_8_SkColorType support here via a special encoding (see below) using |
+ // a 32-bit texture to represent an 8-bit image. |
+ // Thus we use generic 32-bit readback in this case. |
+ if (out_color_type == kAlpha_8_SkColorType) { |
+ readback_color_type = kRGBA_8888_SkColorType; |
+ } |
+ |
+ FormatSupport supported = GetReadbackConfig( |
+ readback_color_type, true, &format, &type, &bytes_per_pixel); |
+ |
if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) { |
callback.Run(false); |
return; |
} |
- GLuint texture = ScaleTexture(src_texture, |
- src_size, |
- src_subrect, |
- dst_size, |
- true, |
- (supported == GLHelperReadbackSupport::SWIZZLE), |
- color_type, |
- quality); |
- DCHECK(texture); |
+ GLuint texture = src_texture; |
+ |
+ // Scale texture if needed |
+ // Optimization: SCALER_QUALITY_FAST is just a single bilinear pass, which we |
+ // can do just as well in EncodeTextureAsGrayscale, which we will do if |
+ // out_color_type is kAlpha_8_SkColorType, so let's skip the scaling step |
+ // in that case. |
+ bool scale_texture = out_color_type != kAlpha_8_SkColorType || |
+ quality != GLHelper::SCALER_QUALITY_FAST; |
+ if (scale_texture) { |
+ // Don't swizzle during the scale step for kAlpha_8_SkColorType. |
+ // We will swizzle in the encode step below if needed. |
+ bool scale_swizzle = out_color_type == kAlpha_8_SkColorType |
+ ? false |
+ : supported == GLHelperReadbackSupport::SWIZZLE; |
+ texture = |
+ ScaleTexture(src_texture, |
+ src_size, |
+ src_subrect, |
+ dst_size, |
+ true, |
+ scale_swizzle, |
+ out_color_type == kAlpha_8_SkColorType ? kN32_SkColorType |
+ : out_color_type, |
+ quality); |
+ DCHECK(texture); |
+ } |
+ |
+ gfx::Size readback_texture_size = dst_size; |
+ // Encode texture to grayscale if needed. |
+ if (out_color_type == kAlpha_8_SkColorType) { |
+ // Do the vertical flip here if we haven't already done it when we scaled |
+ // the texture. |
+ bool encode_as_grayscale_vertical_flip = !scale_texture; |
+ // EncodeTextureAsGrayscale by default creates a texture which should be |
+ // read back as RGBA, so need to swizzle if the readback format is BGRA. |
+ bool encode_as_grayscale_swizzle = format == GL_BGRA_EXT; |
+ GLuint tmp_texture = |
+ EncodeTextureAsGrayscale(texture, |
+ dst_size, |
+ &readback_texture_size, |
+ encode_as_grayscale_vertical_flip, |
+ encode_as_grayscale_swizzle); |
+ // If the scaled texture was created - delete it |
+ if (scale_texture) |
+ gl_->DeleteTextures(1, &texture); |
+ texture = tmp_texture; |
+ DCHECK(texture); |
+ } |
+ |
+ // Readback the pixels of the resulting texture |
ScopedFramebuffer dst_framebuffer(gl_); |
ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, |
dst_framebuffer); |
@@ -479,9 +589,14 @@ void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture( |
GL_TEXTURE_2D, |
texture, |
0); |
- ReadbackAsync(dst_size, |
- dst_size.width() * bytes_per_pixel, |
- dst_size.width() * bytes_per_pixel, |
+ |
+ int32 bytes_per_row = out_color_type == kAlpha_8_SkColorType |
+ ? dst_size.width() |
+ : dst_size.width() * bytes_per_pixel; |
+ |
+ ReadbackAsync(readback_texture_size, |
+ bytes_per_row, |
+ bytes_per_row, |
out, |
format, |
type, |
@@ -656,19 +771,18 @@ void GLHelper::CropScaleReadbackAndCleanTexture( |
const gfx::Rect& src_subrect, |
const gfx::Size& dst_size, |
unsigned char* out, |
- const SkColorType color_type, |
+ const SkColorType out_color_type, |
const base::Callback<void(bool)>& callback, |
GLHelper::ScalerQuality quality) { |
InitCopyTextToImpl(); |
- copy_texture_to_impl_->CropScaleReadbackAndCleanTexture( |
- src_texture, |
- src_size, |
- src_subrect, |
- dst_size, |
- out, |
- color_type, |
- callback, |
- quality); |
+ copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture, |
+ src_size, |
+ src_subrect, |
+ dst_size, |
+ out, |
+ out_color_type, |
+ callback, |
+ quality); |
} |
void GLHelper::CropScaleReadbackAndCleanMailbox( |
@@ -678,15 +792,18 @@ void GLHelper::CropScaleReadbackAndCleanMailbox( |
const gfx::Rect& src_subrect, |
const gfx::Size& dst_size, |
unsigned char* out, |
- const SkColorType color_type, |
+ const SkColorType out_color_type, |
const base::Callback<void(bool)>& callback, |
GLHelper::ScalerQuality quality) { |
GLuint mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point); |
- CropScaleReadbackAndCleanTexture( |
- mailbox_texture, src_size, src_subrect, dst_size, out, |
- color_type, |
- callback, |
- quality); |
+ CropScaleReadbackAndCleanTexture(mailbox_texture, |
+ src_size, |
+ src_subrect, |
+ dst_size, |
+ out, |
+ out_color_type, |
+ callback, |
+ quality); |
gl_->DeleteTextures(1, &mailbox_texture); |
} |
@@ -901,6 +1018,8 @@ const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = { |
-0.148f, -0.291f, 0.439f, 0.5f}; |
const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = { |
0.439f, -0.368f, -0.071f, 0.5f}; |
+const float GLHelper::CopyTextureToImpl::kRGBtoGrayscaleColorWeights[] = { |
+ 0.213f, 0.715f, 0.072f, 0.0f}; |
// YUV readback constructors. Initiates the main scaler pipeline and |
// one planar scaler for each of the Y, U and V planes. |