#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
+#include "content/common/gpu/client/gl_helper_readback_support.h"
#include "content/common/gpu/client/gl_helper_scaling.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
#include "third_party/skia/include/core/SkRegion.h"
namespace {
+class ScopedFlush {
+ public:
+ explicit ScopedFlush(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
+
+ ~ScopedFlush() { gl_->Flush(); }
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFlush);
+};
+
// Helper class for allocating and holding an RGBA texture of a given
// size and an associated framebuffer.
class TextureFrameBufferPair {
} // namespace
namespace content {
+typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
// Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
// the data needed for it.
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
unsigned char* out,
- const SkBitmap::Config config,
+ const SkColorType out_color_type,
const base::Callback<void(bool)>& callback,
GLHelper::ScalerQuality quality);
void ReadbackTextureSync(GLuint texture,
const gfx::Rect& src_rect,
unsigned char* out,
- SkBitmap::Config format);
+ SkColorType format);
void ReadbackTextureAsync(GLuint texture,
const gfx::Size& dst_size,
unsigned char* out,
- SkBitmap::Config config,
+ SkColorType color_type,
const base::Callback<void(bool)>& callback);
// Reads back bytes from the currently bound frame buffer.
int32 bytes_per_row, // generally dst_size.width() * 4
int32 row_stride_bytes, // generally dst_size.width() * 4
unsigned char* out,
- const SkBitmap::Config config,
+ GLenum format,
+ GLenum type,
+ size_t bytes_per_pixel,
const base::Callback<void(bool)>& callback);
void ReadbackPlane(TextureFrameBufferPair* source,
int plane,
int size_shift,
const gfx::Rect& dst_subrect,
+ ReadbackSwizzle swizzle,
const base::Callback<void(bool)>& callback);
GLuint CopyAndScaleTexture(GLuint texture,
// 0 if GL_EXT_draw_buffers is not available.
GLint MaxDrawBuffers() const { return max_draw_buffers_; }
+ FormatSupport GetReadbackConfig(SkColorType color_type,
+ bool can_swizzle,
+ GLenum* format,
+ GLenum* type,
+ size_t* bytes_per_pixel);
+
private:
// A single request to CropScaleReadbackAndCleanTexture.
// The main thread can cancel the request, before it's handled by the helper
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Rect& dst_subrect,
- bool flip_vertically);
+ bool flip_vertically,
+ ReadbackSwizzle swizzle);
virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
uint32 sync_point,
CopyTextureToImpl* copy_impl_;
gfx::Size dst_size_;
gfx::Rect dst_subrect_;
+ ReadbackSwizzle swizzle_;
ScalerHolder scaler_;
ScalerHolder y_;
ScalerHolder u_;
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Rect& dst_subrect,
- bool flip_vertically);
+ bool flip_vertically,
+ ReadbackSwizzle swizzle);
virtual void ReadbackYUV(const gpu::Mailbox& mailbox,
uint32 sync_point,
gfx::Size dst_size_;
gfx::Rect dst_subrect_;
GLHelper::ScalerQuality quality_;
+ ReadbackSwizzle swizzle_;
ScalerHolder scaler_;
scoped_ptr<content::GLHelperScaling::ShaderInterface> pass1_shader_;
scoped_ptr<content::GLHelperScaling::ShaderInterface> pass2_shader_;
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
- SkBitmap::Config config,
+ 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);
static const float kRGBtoYColorWeights[];
static const float kRGBtoUColorWeights[];
static const float kRGBtoVColorWeights[];
+ static const float kRGBtoGrayscaleColorWeights[];
GLES2Interface* gl_;
gpu::ContextSupport* context_support_;
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
- SkBitmap::Config config,
+ SkColorType color_type,
GLHelper::ScalerQuality quality) {
+ GLuint dst_texture = 0u;
+ gl_->GenTextures(1, &dst_texture);
+ {
+ GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
- bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
- (config == SkBitmap::kARGB_8888_Config));
- if (!format_support) {
- DCHECK(format_support);
- return 0;
+ // Use GL_RGBA for destination/temporary texture unless we're working with
+ // 16-bit data
+ if (color_type == kRGB_565_SkColorType) {
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ }
+
+ gl_->TexImage2D(GL_TEXTURE_2D,
+ 0,
+ format,
+ dst_size.width(),
+ dst_size.height(),
+ 0,
+ format,
+ type,
+ NULL);
}
scoped_ptr<ScalerInterface> scaler(
helper_->CreateScaler(quality,
dst_size,
vertically_flip_texture,
swizzle));
+ scaler->Scale(src_texture, dst_texture);
+ 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;
- // Start with ARGB8888 params as any other format which is not
- // supported is already asserted above.
- GLenum format = GL_RGBA , type = GL_UNSIGNED_BYTE;
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);
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- // Do nothing params already set.
- break;
- case SkBitmap::kRGB_565_Config:
- format = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- default:
- NOTREACHED();
- break;
- }
gl_->TexImage2D(GL_TEXTURE_2D,
0,
- format,
- dst_size.width(),
- dst_size.height(),
+ GL_RGBA,
+ encoded_texture_size->width(),
+ encoded_texture_size->height(),
0,
- format,
- type,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
NULL);
}
- scaler->Scale(src_texture, dst_texture);
+
+ 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;
}
int32 bytes_per_row,
int32 row_stride_bytes,
unsigned char* out,
- const SkBitmap::Config config,
+ GLenum format,
+ GLenum type,
+ size_t bytes_per_pixel,
const base::Callback<void(bool)>& callback) {
- bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
- (config == SkBitmap::kARGB_8888_Config));
- if (!format_support) {
- DCHECK(format_support);
- callback.Run(false);
- return;
- }
+ TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::ReadbackAsync");
Request* request =
new Request(dst_size, bytes_per_row, row_stride_bytes, out, callback);
request_queue_.push(request);
request->buffer = 0u;
- // Start with ARGB8888 params as any other format which is not
- // supported is already asserted above.
- GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE;
- int bytes_per_pixel = 4;
-
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- // Do nothing params already set.
- break;
- case SkBitmap::kRGB_565_Config:
- format = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- bytes_per_pixel = 2;
- break;
- default:
- NOTREACHED();
- break;
- }
+
gl_->GenBuffers(1, &request->buffer);
gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
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 SkBitmap::Config bitmap_config,
+ const SkColorType out_color_type,
const base::Callback<void(bool)>& callback,
GLHelper::ScalerQuality quality) {
- bool format_support = ((bitmap_config == SkBitmap::kRGB_565_Config) ||
- (bitmap_config == SkBitmap::kARGB_8888_Config));
- if (!format_support) {
- DCHECK(format_support);
+ GLenum format, type;
+ size_t 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,
-#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
- true,
-#else
- false,
-#endif
- bitmap_config,
- 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);
GL_TEXTURE_2D,
texture,
0);
- int bytes_per_pixel = 4;
- switch (bitmap_config) {
- case SkBitmap::kARGB_8888_Config:
- // Do nothing params already set.
- break;
- case SkBitmap::kRGB_565_Config:
- bytes_per_pixel = 2;
- break;
- default:
- NOTREACHED();
- break;
- }
- 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,
- bitmap_config,
+ format,
+ type,
+ bytes_per_pixel,
callback);
gl_->DeleteTextures(1, &texture);
}
-void GLHelper::CopyTextureToImpl::ReadbackTextureSync(GLuint texture,
- const gfx::Rect& src_rect,
- unsigned char* out,
- SkBitmap::Config config) {
- DCHECK((config == SkBitmap::kRGB_565_Config) ||
- (config == SkBitmap::kARGB_8888_Config));
+void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
+ GLuint texture,
+ const gfx::Rect& src_rect,
+ unsigned char* out,
+ SkColorType color_type) {
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport supported =
+ GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
+ if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
+ return;
+ }
+
ScopedFramebuffer dst_framebuffer(gl_);
ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
dst_framebuffer);
ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
gl_->FramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
- GLenum format = (config == SkBitmap::kRGB_565_Config) ?
- GL_RGB :
- GL_RGBA;
- GLenum type = (config == SkBitmap::kRGB_565_Config) ?
- GL_UNSIGNED_SHORT_5_6_5 :
- GL_UNSIGNED_BYTE;
gl_->ReadPixels(src_rect.x(),
src_rect.y(),
src_rect.width(),
GLuint texture,
const gfx::Size& dst_size,
unsigned char* out,
- SkBitmap::Config config,
+ SkColorType color_type,
const base::Callback<void(bool)>& callback) {
- // Only ARGB888 and RGB565 supported as of now.
- bool format_support = ((config == SkBitmap::kRGB_565_Config) ||
- (config == SkBitmap::kARGB_8888_Config));
- if (!format_support) {
- DCHECK(format_support);
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport supported =
+ GetReadbackConfig(color_type, false, &format, &type, &bytes_per_pixel);
+ if (supported == GLHelperReadbackSupport::NOT_SUPPORTED) {
+ callback.Run(false);
return;
}
+
ScopedFramebuffer dst_framebuffer(gl_);
ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
dst_framebuffer);
GL_TEXTURE_2D,
texture,
0);
- int bytes_per_pixel = (config == SkBitmap::kRGB_565_Config) ? 2 : 4;
ReadbackAsync(dst_size,
dst_size.width() * bytes_per_pixel,
dst_size.width() * bytes_per_pixel,
out,
- config,
+ format,
+ type,
+ bytes_per_pixel,
callback);
}
dst_size,
vertically_flip_texture,
false,
- SkBitmap::kARGB_8888_Config,
+ kRGBA_8888_SkColorType, // GL_RGBA
quality);
}
}
}
+FormatSupport GLHelper::CopyTextureToImpl::GetReadbackConfig(
+ SkColorType color_type,
+ bool can_swizzle,
+ GLenum* format,
+ GLenum* type,
+ size_t* bytes_per_pixel) {
+ return helper_->readback_support_->GetReadbackConfig(
+ color_type, can_swizzle, format, type, bytes_per_pixel);
+}
+
GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
: gl_(gl),
context_support_(context_support),
- initialized_565_format_check_(false),
- support_565_format_(false) {}
+ readback_support_(new GLHelperReadbackSupport(gl)) {}
GLHelper::~GLHelper() {}
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
unsigned char* out,
- const SkBitmap::Config config,
- const base::Callback<void(bool)>& callback) {
+ 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,
- config,
- callback,
- GLHelper::SCALER_QUALITY_FAST);
+ copy_texture_to_impl_->CropScaleReadbackAndCleanTexture(src_texture,
+ src_size,
+ src_subrect,
+ dst_size,
+ out,
+ out_color_type,
+ callback,
+ quality);
}
void GLHelper::CropScaleReadbackAndCleanMailbox(
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
unsigned char* out,
- const SkBitmap::Config bitmap_config,
- const base::Callback<void(bool)>& callback) {
+ 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,
- bitmap_config,
- callback);
+ CropScaleReadbackAndCleanTexture(mailbox_texture,
+ src_size,
+ src_subrect,
+ dst_size,
+ out,
+ out_color_type,
+ callback,
+ quality);
gl_->DeleteTextures(1, &mailbox_texture);
}
void GLHelper::ReadbackTextureSync(GLuint texture,
const gfx::Rect& src_rect,
unsigned char* out,
- SkBitmap::Config format) {
+ SkColorType format) {
InitCopyTextToImpl();
copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
}
GLuint texture,
const gfx::Size& dst_size,
unsigned char* out,
- SkBitmap::Config config,
+ SkColorType color_type,
const base::Callback<void(bool)>& callback) {
InitCopyTextToImpl();
copy_texture_to_impl_->ReadbackTextureAsync(texture,
dst_size,
out,
- config,
+ color_type,
callback);
}
gl_->WaitSyncPointCHROMIUM(sync_point);
}
-gpu::Mailbox GLHelper::ProduceMailboxFromTexture(GLuint texture_id,
- uint32* sync_point) {
+gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
+ GLuint texture_id) {
gpu::Mailbox mailbox;
gl_->GenMailboxCHROMIUM(mailbox.name);
- if (mailbox.IsZero()) {
- *sync_point = 0;
- return mailbox;
- }
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture_id);
- gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
- *sync_point = InsertSyncPoint();
- return mailbox;
+ gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
+ return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
}
GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
return 0;
if (sync_point)
WaitSyncPoint(sync_point);
- GLuint texture = CreateTexture();
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
- gl_->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ GLuint texture =
+ gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
return texture;
}
GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
}
-bool GLHelper::CanUseRgb565Readback() {
- if(initialized_565_format_check_){
- return support_565_format_;
- }
- const int kTestSize = 64;
- GLuint dst_texture = 0u;
- gl_->GenTextures(1, &dst_texture);
- ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, dst_texture);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl_->TexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGB,
- kTestSize,
- kTestSize,
- 0,
- GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5,
- NULL);
- ScopedFramebuffer dst_framebuffer(gl_);
- ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
- dst_framebuffer);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- dst_texture,
- 0);
- GLint ext_format = 0, ext_type = 0;
- gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &ext_format);
- gl_->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &ext_type);
- gl_->DeleteTextures(1, &dst_texture);
- if ((ext_format == GL_RGB) && (ext_type == GL_UNSIGNED_SHORT_5_6_5)) {
- support_565_format_ = true;
- }
- initialized_565_format_check_ = true;
- return support_565_format_;
+void GLHelper::Flush() {
+ gl_->Flush();
}
void GLHelper::CopyTextureToImpl::ReadbackPlane(
int plane,
int size_shift,
const gfx::Rect& dst_subrect,
+ ReadbackSwizzle swizzle,
const base::Callback<void(bool)>& callback) {
gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
dst_subrect.width() >> size_shift,
target->stride(plane),
target->data(plane) + offset,
- SkBitmap::kARGB_8888_Config,
+ (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ 4,
callback);
}
-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.
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Rect& dst_subrect,
- bool flip_vertically)
+ bool flip_vertically,
+ ReadbackSwizzle swizzle)
: gl_(gl),
copy_impl_(copy_impl),
dst_size_(dst_size),
dst_subrect_(dst_subrect),
+ swizzle_(swizzle),
scaler_(gl,
scaler_impl->CreateScaler(quality,
src_size,
dst_subrect.height()),
gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
false,
+ (swizzle == kSwizzleBGRA),
kRGBtoYColorWeights)),
u_(gl,
scaler_impl->CreatePlanarScaler(
gfx::Size((dst_subrect.width() + 7) / 8,
(dst_subrect.height() + 1) / 2),
false,
+ (swizzle == kSwizzleBGRA),
kRGBtoUColorWeights)),
v_(gl,
scaler_impl->CreatePlanarScaler(
gfx::Size((dst_subrect.width() + 7) / 8,
(dst_subrect.height() + 1) / 2),
false,
+ (swizzle == kSwizzleBGRA),
kRGBtoVColorWeights)) {
DCHECK(!(dst_size.width() & 1));
DCHECK(!(dst_size.height() & 1));
media::VideoFrame::kYPlane,
0,
dst_subrect_,
+ swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(u_.texture_and_framebuffer(),
target,
media::VideoFrame::kUPlane,
1,
dst_subrect_,
+ swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(
v_.texture_and_framebuffer(),
media::VideoFrame::kVPlane,
1,
dst_subrect_,
+ swizzle_,
base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
- media::LetterboxYUV(target, dst_subrect_);
+ media::LetterboxYUV(target.get(), dst_subrect_);
}
// YUV readback constructors. Initiates the main scaler pipeline and
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Rect& dst_subrect,
- bool flip_vertically)
+ bool flip_vertically,
+ ReadbackSwizzle swizzle)
: gl_(gl),
copy_impl_(copy_impl),
dst_size_(dst_size),
dst_subrect_(dst_subrect),
quality_(quality),
+ swizzle_(swizzle),
scaler_(gl,
scaler_impl->CreateScaler(quality,
src_size,
gfx::Rect(0, 0, (dst_subrect.width() + 3) & ~3, dst_subrect.height()),
gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
flip_vertically,
+ (swizzle == kSwizzleBGRA),
GLHelperScaling::SHADER_YUV_MRT_PASS1)),
pass2_shader_(scaler_impl->CreateYuvMrtShader(
gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
gfx::Size((dst_subrect.width() + 7) / 8,
(dst_subrect.height() + 1) / 2),
false,
+ (swizzle == kSwizzleBGRA),
GLHelperScaling::SHADER_YUV_MRT_PASS2)),
y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
uv_(gl),
media::VideoFrame::kYPlane,
0,
dst_subrect_,
+ swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(&u_,
target,
media::VideoFrame::kUPlane,
1,
dst_subrect_,
+ swizzle_,
base::Bind(&nullcallback));
copy_impl_->ReadbackPlane(
&v_,
media::VideoFrame::kVPlane,
1,
dst_subrect_,
+ swizzle_,
base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
- media::LetterboxYUV(target, dst_subrect_);
+ media::LetterboxYUV(target.get(), dst_subrect_);
+}
+
+bool GLHelper::IsReadbackConfigSupported(SkColorType color_type) {
+ DCHECK(readback_support_.get());
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport support = readback_support_->GetReadbackConfig(
+ color_type, false, &format, &type, &bytes_per_pixel);
+
+ return (support == GLHelperReadbackSupport::SUPPORTED);
}
ReadbackYUVInterface* GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
bool flip_vertically,
bool use_mrt) {
helper_->InitScalerImpl();
+ // Just query if the best readback configuration needs a swizzle In
+ // ReadbackPlane() we will choose GL_RGBA/GL_BGRA_EXT based on swizzle
+ GLenum format, type;
+ size_t bytes_per_pixel;
+ FormatSupport supported = GetReadbackConfig(
+ kRGBA_8888_SkColorType, true, &format, &type, &bytes_per_pixel);
+ DCHECK((format == GL_RGBA || format == GL_BGRA_EXT) &&
+ type == GL_UNSIGNED_BYTE);
+
+ ReadbackSwizzle swizzle = kSwizzleNone;
+ if (supported == GLHelperReadbackSupport::SWIZZLE)
+ swizzle = kSwizzleBGRA;
+
if (max_draw_buffers_ >= 2 && use_mrt) {
return new ReadbackYUV_MRT(gl_,
this,
src_subrect,
dst_size,
dst_subrect,
- flip_vertically);
+ flip_vertically,
+ swizzle);
}
return new ReadbackYUVImpl(gl_,
this,
src_subrect,
dst_size,
dst_subrect,
- flip_vertically);
+ flip_vertically,
+ swizzle);
}
ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(