#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/WebKit/public/platform/WebCString.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
-#include "ui/gl/gl_bindings.h"
-using WebKit::WebGLId;
-using WebKit::WebGraphicsContext3D;
+using gpu::gles2::GLES2Interface;
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 {
public:
- TextureFrameBufferPair(WebGraphicsContext3D* context,
- gfx::Size size)
- : texture_(context, context->createTexture()),
- framebuffer_(context, context->createFramebuffer()),
- size_(size) {
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context,
- texture_);
- context->texImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- size.width(),
- size.height(),
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- NULL);
+ TextureFrameBufferPair(GLES2Interface* gl, gfx::Size size)
+ : texture_(gl), framebuffer_(gl), size_(size) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, texture_);
+ gl->TexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ size.width(),
+ size.height(),
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL);
content::ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(
- context,
- framebuffer_);
- context->framebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- texture_,
- 0);
+ gl, framebuffer_);
+ gl->FramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0);
}
- WebGLId texture() const { return texture_.id(); }
- WebGLId framebuffer() const { return framebuffer_.id(); }
+ GLuint texture() const { return texture_.id(); }
+ GLuint framebuffer() const { return framebuffer_.id(); }
gfx::Size size() const { return size_; }
private:
// when the output of a scaler is to be sent to a readback.
class ScalerHolder {
public:
- ScalerHolder(WebGraphicsContext3D* context,
- content::GLHelper::ScalerInterface *scaler)
- : texture_and_framebuffer_(context, scaler->DstSize()),
- scaler_(scaler) {
- }
+ ScalerHolder(GLES2Interface* gl, content::GLHelper::ScalerInterface* scaler)
+ : texture_and_framebuffer_(gl, scaler->DstSize()), scaler_(scaler) {}
- void Scale(WebKit::WebGLId src_texture) {
+ void Scale(GLuint src_texture) {
scaler_->Scale(src_texture, texture_and_framebuffer_.texture());
}
content::GLHelper::ScalerInterface* scaler() const { return scaler_.get(); }
- TextureFrameBufferPair *texture_and_framebuffer() {
+ TextureFrameBufferPair* texture_and_framebuffer() {
return &texture_and_framebuffer_;
}
- WebGLId texture() const { return texture_and_framebuffer_.texture(); }
+ GLuint texture() const { return texture_and_framebuffer_.texture(); }
private:
TextureFrameBufferPair texture_and_framebuffer_;
} // namespace
namespace content {
+typedef GLHelperReadbackSupport::FormatSupport FormatSupport;
// Implements GLHelper::CropScaleReadbackAndCleanTexture and encapsulates
// the data needed for it.
-class GLHelper::CopyTextureToImpl :
- public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
+class GLHelper::CopyTextureToImpl
+ : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
public:
- CopyTextureToImpl(WebGraphicsContext3D* context,
+ CopyTextureToImpl(GLES2Interface* gl,
gpu::ContextSupport* context_support,
GLHelper* helper)
- : context_(context),
+ : gl_(gl),
context_support_(context_support),
helper_(helper),
- flush_(context),
+ flush_(gl),
max_draw_buffers_(0) {
- std::string extensions_string = " " +
- UTF16ToASCII(context_->getString(GL_EXTENSIONS)) + " ";
+ const GLubyte* extensions = gl_->GetString(GL_EXTENSIONS);
+ if (!extensions)
+ return;
+ std::string extensions_string =
+ " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
if (extensions_string.find(" GL_EXT_draw_buffers ") != std::string::npos) {
- context_->getIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers_);
+ gl_->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
}
}
- ~CopyTextureToImpl() {
- CancelRequests();
- }
+ ~CopyTextureToImpl() { CancelRequests(); }
- WebGLId ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
- uint32 sync_point) {
+ GLuint ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
+ uint32 sync_point) {
return helper_->ConsumeMailboxToTexture(mailbox, sync_point);
}
void CropScaleReadbackAndCleanTexture(
- WebGLId src_texture,
+ GLuint src_texture,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
unsigned char* out,
+ const SkColorType out_color_type,
const base::Callback<void(bool)>& callback,
GLHelper::ScalerQuality quality);
- void ReadbackTextureSync(WebGLId texture,
+ void ReadbackTextureSync(GLuint texture,
const gfx::Rect& src_rect,
- unsigned char* out);
+ unsigned char* out,
+ SkColorType format);
+
+ void ReadbackTextureAsync(GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback);
// Reads back bytes from the currently bound frame buffer.
// Note that dst_size is specified in bytes, not pixels.
- void ReadbackAsync(
- const gfx::Size& dst_size,
- int32 bytes_per_row, // generally dst_size.width() * 4
- int32 row_stride_bytes, // generally dst_size.width() * 4
- unsigned char* out,
- const base::Callback<void(bool)>& callback);
+ void ReadbackAsync(const gfx::Size& dst_size,
+ int32 bytes_per_row, // generally dst_size.width() * 4
+ int32 row_stride_bytes, // generally dst_size.width() * 4
+ unsigned char* out,
+ GLenum format,
+ GLenum type,
+ size_t bytes_per_pixel,
+ const base::Callback<void(bool)>& callback);
void ReadbackPlane(TextureFrameBufferPair* source,
const scoped_refptr<media::VideoFrame>& target,
int plane,
int size_shift,
const gfx::Rect& dst_subrect,
+ ReadbackSwizzle swizzle,
const base::Callback<void(bool)>& callback);
- WebKit::WebGLId CopyAndScaleTexture(WebGLId texture,
- const gfx::Size& src_size,
- const gfx::Size& dst_size,
- bool vertically_flip_texture,
- GLHelper::ScalerQuality quality);
+ GLuint CopyAndScaleTexture(GLuint texture,
+ const gfx::Size& src_size,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ GLHelper::ScalerQuality quality);
ReadbackYUVInterface* CreateReadbackPipelineYUV(
GLHelper::ScalerQuality quality,
// Returns the maximum number of draw buffers available,
// 0 if GL_EXT_draw_buffers is not available.
- WebKit::WGC3Dint MaxDrawBuffers() const {
- return max_draw_buffers_;
- }
+ 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.
// thread marks that it handles the request by resetting the pixels field
// (meaning it guarantees that the callback with be called).
// In either case, the callback must be called exactly once, and the texture
- // must be deleted by the main thread context.
+ // must be deleted by the main thread gl.
struct Request {
Request(const gfx::Size& size_,
int32 bytes_per_row_,
pixels(pixels_),
callback(callback_),
buffer(0),
- query(0) {
- }
+ query(0) {}
bool done;
gfx::Size size;
unsigned char* pixels;
base::Callback<void(bool)> callback;
GLuint buffer;
- WebKit::WebGLId query;
+ GLuint query;
};
// A readback pipeline that also converts the data to YUV before
// reading it back.
class ReadbackYUVImpl : public ReadbackYUVInterface {
public:
- ReadbackYUVImpl(WebGraphicsContext3D* context,
+ ReadbackYUVImpl(GLES2Interface* gl,
CopyTextureToImpl* copy_impl,
GLHelperScaling* scaler_impl,
GLHelper::ScalerQuality quality,
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,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE;
+ void ReadbackYUV(const gpu::Mailbox& mailbox,
+ uint32 sync_point,
+ const scoped_refptr<media::VideoFrame>& target,
+ const base::Callback<void(bool)>& callback) override;
- virtual ScalerInterface* scaler() OVERRIDE {
- return scaler_.scaler();
- }
+ ScalerInterface* scaler() override { return scaler_.scaler(); }
private:
- WebGraphicsContext3D* context_;
+ GLES2Interface* gl_;
CopyTextureToImpl* copy_impl_;
gfx::Size dst_size_;
gfx::Rect dst_subrect_;
+ ReadbackSwizzle swizzle_;
ScalerHolder scaler_;
ScalerHolder y_;
ScalerHolder u_;
// may not be supported on all platforms.
class ReadbackYUV_MRT : public ReadbackYUVInterface {
public:
- ReadbackYUV_MRT(WebGraphicsContext3D* context,
+ ReadbackYUV_MRT(GLES2Interface* gl,
CopyTextureToImpl* copy_impl,
GLHelperScaling* scaler_impl,
GLHelper::ScalerQuality quality,
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,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback) OVERRIDE;
+ void ReadbackYUV(const gpu::Mailbox& mailbox,
+ uint32 sync_point,
+ const scoped_refptr<media::VideoFrame>& target,
+ const base::Callback<void(bool)>& callback) override;
- virtual ScalerInterface* scaler() OVERRIDE {
- return scaler_.scaler();
- }
+ ScalerInterface* scaler() override { return scaler_.scaler(); }
private:
- WebGraphicsContext3D* context_;
+ GLES2Interface* gl_;
CopyTextureToImpl* copy_impl_;
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_;
// Copies the block of pixels specified with |src_subrect| from |src_texture|,
// scales it to |dst_size|, writes it into a texture, and returns its ID.
// |src_size| is the size of |src_texture|.
- WebGLId ScaleTexture(WebGLId src_texture,
- const gfx::Size& src_size,
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- bool vertically_flip_texture,
- bool swizzle,
- GLHelper::ScalerQuality quality);
+ GLuint ScaleTexture(GLuint src_texture,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle,
+ 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);
+ void ReadbackDone(Request *request, int bytes_per_pixel);
void FinishRequest(Request* request, bool result);
void CancelRequests();
static const float kRGBtoYColorWeights[];
static const float kRGBtoUColorWeights[];
static const float kRGBtoVColorWeights[];
+ static const float kRGBtoGrayscaleColorWeights[];
- WebGraphicsContext3D* context_;
+ GLES2Interface* gl_;
gpu::ContextSupport* context_support_;
GLHelper* helper_;
ScopedFlush flush_;
std::queue<Request*> request_queue_;
- WebKit::WGC3Dint max_draw_buffers_;
+ GLint max_draw_buffers_;
};
-GLHelper::ScalerInterface* GLHelper::CreateScaler(
- ScalerQuality quality,
- const gfx::Size& src_size,
- const gfx::Rect& src_subrect,
- const gfx::Size& dst_size,
- bool vertically_flip_texture,
- bool swizzle) {
+GLHelper::ScalerInterface* GLHelper::CreateScaler(ScalerQuality quality,
+ const gfx::Size& src_size,
+ const gfx::Rect& src_subrect,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ bool swizzle) {
InitScalerImpl();
return scaler_impl_->CreateScaler(quality,
src_size,
swizzle);
}
-WebGLId GLHelper::CopyTextureToImpl::ScaleTexture(
- WebGLId src_texture,
+GLuint GLHelper::CopyTextureToImpl::ScaleTexture(
+ GLuint src_texture,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
bool vertically_flip_texture,
bool swizzle,
+ 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);
+
+ // 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,
src_size,
dst_size,
vertically_flip_texture,
swizzle));
+ scaler->Scale(src_texture, dst_texture);
+ return dst_texture;
+}
- WebGLId dst_texture = context_->createTexture();
+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(context_, dst_texture);
- context_->texImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- dst_size.width(),
- dst_size.height(),
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- NULL);
+ 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);
}
- 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,
+ GLenum format,
+ GLenum type,
+ size_t bytes_per_pixel,
const base::Callback<void(bool)>& callback) {
- Request* request = new Request(dst_size,
- bytes_per_row,
- row_stride_bytes,
- out,
- callback);
+ 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 = context_->createBuffer();
- context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- request->buffer);
- context_->bufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- 4 * dst_size.GetArea(),
- NULL,
- GL_STREAM_READ);
-
- request->query = context_->createQueryEXT();
- context_->beginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM,
- request->query);
- context_->readPixels(0, 0, dst_size.width(), dst_size.height(),
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- context_->endQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
- context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ request->buffer = 0u;
+
+ gl_->GenBuffers(1, &request->buffer);
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
+ gl_->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
+ bytes_per_pixel * dst_size.GetArea(),
+ NULL,
+ GL_STREAM_READ);
+
+ request->query = 0u;
+ gl_->GenQueriesEXT(1, &request->query);
+ gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, request->query);
+ gl_->ReadPixels(0,
+ 0,
+ dst_size.width(),
+ dst_size.height(),
+ format,
+ type,
+ NULL);
+ gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
context_support_->SignalQuery(
request->query,
- base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), request));
+ base::Bind(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(),
+ request, bytes_per_pixel));
}
-
void GLHelper::CopyTextureToImpl::CropScaleReadbackAndCleanTexture(
- WebGLId src_texture,
+ GLuint src_texture,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
unsigned char* out,
+ const SkColorType out_color_type,
const base::Callback<void(bool)>& callback,
GLHelper::ScalerQuality quality) {
- WebGLId texture = ScaleTexture(src_texture,
- src_size,
- src_subrect,
+ 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 = 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,
- true,
-#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT
- true,
-#else
- false,
-#endif
- quality);
- ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer());
- ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_,
+ &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);
- ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
- context_->framebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- texture,
- 0);
- ReadbackAsync(dst_size,
- dst_size.width() * 4,
- dst_size.width() * 4,
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ texture,
+ 0);
+
+ 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,
+ bytes_per_pixel,
callback);
- context_->deleteTexture(texture);
+ gl_->DeleteTextures(1, &texture);
}
void GLHelper::CopyTextureToImpl::ReadbackTextureSync(
- WebGLId texture,
+ GLuint texture,
const gfx::Rect& src_rect,
- unsigned char* out) {
- ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer());
- ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_,
+ 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(context_, texture);
- context_->framebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- texture,
- 0);
- context_->readPixels(src_rect.x(),
- src_rect.y(),
- src_rect.width(),
- src_rect.height(),
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- out);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ gl_->ReadPixels(src_rect.x(),
+ src_rect.y(),
+ src_rect.width(),
+ src_rect.height(),
+ format,
+ type,
+ out);
+}
+
+void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
+ GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback) {
+ 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);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ texture,
+ 0);
+ ReadbackAsync(dst_size,
+ dst_size.width() * bytes_per_pixel,
+ dst_size.width() * bytes_per_pixel,
+ out,
+ format,
+ type,
+ bytes_per_pixel,
+ callback);
}
-WebKit::WebGLId GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
- WebGLId src_texture,
+GLuint GLHelper::CopyTextureToImpl::CopyAndScaleTexture(
+ GLuint src_texture,
const gfx::Size& src_size,
const gfx::Size& dst_size,
bool vertically_flip_texture,
dst_size,
vertically_flip_texture,
false,
+ kRGBA_8888_SkColorType, // GL_RGBA
quality);
}
-void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request) {
+void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request,
+ int bytes_per_pixel) {
TRACE_EVENT0("mirror",
"GLHelper::CopyTextureToImpl::CheckReadbackFramebufferComplete");
finished_request->done = true;
bool result = false;
if (request->buffer != 0) {
- context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- request->buffer);
- unsigned char* data = static_cast<unsigned char *>(
- context_->mapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, request->buffer);
+ unsigned char* data = static_cast<unsigned char*>(gl_->MapBufferCHROMIUM(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
if (data) {
result = true;
- if (request->bytes_per_row == request->size.width() * 4 &&
+ if (request->bytes_per_row == request->size.width() * bytes_per_pixel &&
request->bytes_per_row == request->row_stride_bytes) {
- memcpy(request->pixels, data, request->size.GetArea() * 4);
+ memcpy(request->pixels, data,
+ request->size.GetArea() * bytes_per_pixel);
} else {
unsigned char* out = request->pixels;
for (int y = 0; y < request->size.height(); y++) {
memcpy(out, data, request->bytes_per_row);
out += request->row_stride_bytes;
- data += request->size.width() * 4;
+ data += request->size.width() * bytes_per_pixel;
}
}
- context_->unmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
+ gl_->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
}
- context_->bindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
}
-
FinishRequest(request, result);
}
}
-void GLHelper::CopyTextureToImpl::FinishRequest(Request* request,
- bool result) {
+void GLHelper::CopyTextureToImpl::FinishRequest(Request* request, bool result) {
TRACE_EVENT0("mirror", "GLHelper::CopyTextureToImpl::FinishRequest");
DCHECK(request_queue_.front() == request);
request_queue_.pop();
request->callback.Run(result);
- ScopedFlush flush(context_);
+ ScopedFlush flush(gl_);
if (request->query != 0) {
- context_->deleteQueryEXT(request->query);
+ gl_->DeleteQueriesEXT(1, &request->query);
request->query = 0;
}
if (request->buffer != 0) {
- context_->deleteBuffer(request->buffer);
+ gl_->DeleteBuffers(1, &request->buffer);
request->buffer = 0;
}
delete request;
}
}
-GLHelper::GLHelper(WebKit::WebGraphicsContext3D* context,
- gpu::ContextSupport* context_support)
- : context_(context),
- context_support_(context_support) {
+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() {
-}
+GLHelper::GLHelper(GLES2Interface* gl, gpu::ContextSupport* context_support)
+ : gl_(gl),
+ context_support_(context_support),
+ readback_support_(new GLHelperReadbackSupport(gl)) {}
+
+GLHelper::~GLHelper() {}
void GLHelper::CropScaleReadbackAndCleanTexture(
- WebGLId src_texture,
+ GLuint src_texture,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
unsigned char* out,
- 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,
- 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 base::Callback<void(bool)>& callback) {
- WebGLId mailbox_texture = ConsumeMailboxToTexture(src_mailbox, sync_point);
- CropScaleReadbackAndCleanTexture(
- mailbox_texture, src_size, src_subrect, dst_size, out, callback);
- context_->deleteTexture(mailbox_texture);
+ 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,
+ out_color_type,
+ callback,
+ quality);
+ gl_->DeleteTextures(1, &mailbox_texture);
}
-void GLHelper::ReadbackTextureSync(WebKit::WebGLId texture,
+void GLHelper::ReadbackTextureSync(GLuint texture,
const gfx::Rect& src_rect,
- unsigned char* out) {
+ unsigned char* out,
+ SkColorType format) {
InitCopyTextToImpl();
- copy_texture_to_impl_->ReadbackTextureSync(texture,
- src_rect,
- out);
+ copy_texture_to_impl_->ReadbackTextureSync(texture, src_rect, out, format);
}
-WebKit::WebGLId GLHelper::CopyTexture(WebKit::WebGLId texture,
- const gfx::Size& size) {
+void GLHelper::ReadbackTextureAsync(
+ GLuint texture,
+ const gfx::Size& dst_size,
+ unsigned char* out,
+ SkColorType color_type,
+ const base::Callback<void(bool)>& callback) {
+ InitCopyTextToImpl();
+ copy_texture_to_impl_->ReadbackTextureAsync(texture,
+ dst_size,
+ out,
+ color_type,
+ callback);
+}
+
+GLuint GLHelper::CopyTexture(GLuint texture, const gfx::Size& size) {
InitCopyTextToImpl();
return copy_texture_to_impl_->CopyAndScaleTexture(
- texture,
- size,
- size,
- false,
- GLHelper::SCALER_QUALITY_FAST);
+ texture, size, size, false, GLHelper::SCALER_QUALITY_FAST);
}
-WebKit::WebGLId GLHelper::CopyAndScaleTexture(
- WebKit::WebGLId texture,
- const gfx::Size& src_size,
- const gfx::Size& dst_size,
- bool vertically_flip_texture,
- ScalerQuality quality) {
+GLuint GLHelper::CopyAndScaleTexture(GLuint texture,
+ const gfx::Size& src_size,
+ const gfx::Size& dst_size,
+ bool vertically_flip_texture,
+ ScalerQuality quality) {
InitCopyTextToImpl();
- return copy_texture_to_impl_->CopyAndScaleTexture(texture,
- src_size,
- dst_size,
- vertically_flip_texture,
- quality);
+ return copy_texture_to_impl_->CopyAndScaleTexture(
+ texture, src_size, dst_size, vertically_flip_texture, quality);
}
-WebGLId GLHelper::CompileShaderFromSource(
- const WebKit::WGC3Dchar* source,
- WebKit::WGC3Denum type) {
- ScopedShader shader(context_, context_->createShader(type));
- context_->shaderSource(shader, source);
- context_->compileShader(shader);
- WebKit::WGC3Dint compile_status = 0;
- context_->getShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+GLuint GLHelper::CompileShaderFromSource(const GLchar* source, GLenum type) {
+ GLuint shader = gl_->CreateShader(type);
+ GLint length = strlen(source);
+ gl_->ShaderSource(shader, 1, &source, &length);
+ gl_->CompileShader(shader);
+ GLint compile_status = 0;
+ gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
if (!compile_status) {
- LOG(ERROR) << std::string(context_->getShaderInfoLog(shader).utf8());
+ GLint log_length = 0;
+ gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
+ if (log_length) {
+ scoped_ptr<GLchar[]> log(new GLchar[log_length]);
+ GLsizei returned_log_length = 0;
+ gl_->GetShaderInfoLog(
+ shader, log_length, &returned_log_length, log.get());
+ LOG(ERROR) << std::string(log.get(), returned_log_length);
+ }
+ gl_->DeleteShader(shader);
return 0;
}
- return shader.Detach();
+ return shader;
}
void GLHelper::InitCopyTextToImpl() {
// Lazily initialize |copy_texture_to_impl_|
if (!copy_texture_to_impl_)
copy_texture_to_impl_.reset(
- new CopyTextureToImpl(context_, context_support_, this));
+ new CopyTextureToImpl(gl_, context_support_, this));
}
void GLHelper::InitScalerImpl() {
// Lazily initialize |scaler_impl_|
if (!scaler_impl_)
- scaler_impl_.reset(new GLHelperScaling(context_, this));
+ scaler_impl_.reset(new GLHelperScaling(gl_, this));
}
-WebKit::WGC3Dint GLHelper::MaxDrawBuffers() {
+GLint GLHelper::MaxDrawBuffers() {
InitCopyTextToImpl();
return copy_texture_to_impl_->MaxDrawBuffers();
}
-void GLHelper::CopySubBufferDamage(WebKit::WebGLId texture,
- WebKit::WebGLId previous_texture,
+void GLHelper::CopySubBufferDamage(GLuint texture,
+ GLuint previous_texture,
const SkRegion& new_damage,
const SkRegion& old_damage) {
SkRegion region(old_damage);
if (region.op(new_damage, SkRegion::kDifference_Op)) {
- ScopedFramebuffer dst_framebuffer(context_,
- context_->createFramebuffer());
- ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(context_,
+ ScopedFramebuffer dst_framebuffer(gl_);
+ ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_,
dst_framebuffer);
- ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
- context_->framebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- previous_texture,
- 0);
+ ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->FramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ previous_texture,
+ 0);
for (SkRegion::Iterator it(region); !it.done(); it.next()) {
const SkIRect& rect = it.rect();
- context_->copyTexSubImage2D(GL_TEXTURE_2D, 0,
- rect.x(), rect.y(),
- rect.x(), rect.y(),
- rect.width(), rect.height());
+ gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
+ 0,
+ rect.x(),
+ rect.y(),
+ rect.x(),
+ rect.y(),
+ rect.width(),
+ rect.height());
}
- context_->flush();
+ gl_->Flush();
}
}
-WebKit::WebGLId GLHelper::CreateTexture() {
- WebKit::WebGLId texture = context_->createTexture();
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_,
- texture);
- context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- context_->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+GLuint GLHelper::CreateTexture() {
+ GLuint texture = 0u;
+ gl_->GenTextures(1, &texture);
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
return texture;
}
-WebKit::WebGLId GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
- uint32 sync_point) {
+void GLHelper::DeleteTexture(GLuint texture_id) {
+ gl_->DeleteTextures(1, &texture_id);
+}
+
+uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
+
+void GLHelper::WaitSyncPoint(uint32 sync_point) {
+ gl_->WaitSyncPointCHROMIUM(sync_point);
+}
+
+gpu::MailboxHolder GLHelper::ProduceMailboxHolderFromTexture(
+ GLuint texture_id) {
+ gpu::Mailbox mailbox;
+ gl_->GenMailboxCHROMIUM(mailbox.name);
+ gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
+ return gpu::MailboxHolder(mailbox, GL_TEXTURE_2D, InsertSyncPoint());
+}
+
+GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
+ uint32 sync_point) {
if (mailbox.IsZero())
return 0;
if (sync_point)
- context_->waitSyncPoint(sync_point);
- WebKit::WebGLId texture = CreateTexture();
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_,
- texture);
- context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ WaitSyncPoint(sync_point);
+ GLuint texture =
+ gl_->CreateAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
return texture;
}
-void GLHelper::ResizeTexture(WebKit::WebGLId texture, const gfx::Size& size) {
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
- context_->texImage2D(GL_TEXTURE_2D, 0, GL_RGB,
- size.width(), size.height(), 0,
- GL_RGB, GL_UNSIGNED_BYTE, NULL);
+void GLHelper::ResizeTexture(GLuint texture, const gfx::Size& size) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->TexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGB,
+ size.width(),
+ size.height(),
+ 0,
+ GL_RGB,
+ GL_UNSIGNED_BYTE,
+ NULL);
+}
+
+void GLHelper::CopyTextureSubImage(GLuint texture, const gfx::Rect& rect) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->CopyTexSubImage2D(GL_TEXTURE_2D,
+ 0,
+ rect.x(),
+ rect.y(),
+ rect.x(),
+ rect.y(),
+ rect.width(),
+ rect.height());
}
-void GLHelper::CopyTextureSubImage(WebKit::WebGLId texture,
- const gfx::Rect& rect) {
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
- context_->copyTexSubImage2D(GL_TEXTURE_2D, 0,
- rect.x(), rect.y(),
- rect.x(), rect.y(), rect.width(), rect.height());
+void GLHelper::CopyTextureFullImage(GLuint texture, const gfx::Size& size) {
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture);
+ gl_->CopyTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGB, 0, 0, size.width(), size.height(), 0);
}
-void GLHelper::CopyTextureFullImage(WebKit::WebGLId texture,
- const gfx::Size& size) {
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, texture);
- context_->copyTexImage2D(GL_TEXTURE_2D, 0,
- GL_RGB,
- 0, 0,
- size.width(), size.height(), 0);
+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) {
- context_->bindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, source->framebuffer());
size_t offset = target->stride(plane) * (dst_subrect.y() >> size_shift) +
(dst_subrect.x() >> size_shift);
- ReadbackAsync(
- source->size(),
- dst_subrect.width() >> size_shift,
- target->stride(plane),
- target->data(plane) + offset,
- callback);
+ ReadbackAsync(source->size(),
+ dst_subrect.width() >> size_shift,
+ target->stride(plane),
+ target->data(plane) + offset,
+ (swizzle == kSwizzleBGRA) ? GL_BGRA_EXT : GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ 4,
+ callback);
}
const float GLHelper::CopyTextureToImpl::kRGBtoYColorWeights[] = {
- 0.257f, 0.504f, 0.098f, 0.0625f
-};
+ 0.257f, 0.504f, 0.098f, 0.0625f};
const float GLHelper::CopyTextureToImpl::kRGBtoUColorWeights[] = {
- -0.148f, -0.291f, 0.439f, 0.5f
-};
+ -0.148f, -0.291f, 0.439f, 0.5f};
const float GLHelper::CopyTextureToImpl::kRGBtoVColorWeights[] = {
- 0.439f, -0.368f, -0.071f, 0.5f
-};
+ 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.
GLHelper::CopyTextureToImpl::ReadbackYUVImpl::ReadbackYUVImpl(
- WebGraphicsContext3D* context,
+ GLES2Interface* gl,
CopyTextureToImpl* copy_impl,
GLHelperScaling* scaler_impl,
GLHelper::ScalerQuality quality,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Rect& dst_subrect,
- bool flip_vertically)
- : context_(context),
+ bool flip_vertically,
+ ReadbackSwizzle swizzle)
+ : gl_(gl),
copy_impl_(copy_impl),
dst_size_(dst_size),
dst_subrect_(dst_subrect),
- scaler_(context, scaler_impl->CreateScaler(
- quality,
- src_size,
- src_subrect,
- dst_subrect.size(),
- flip_vertically,
- false)),
- y_(context, scaler_impl->CreatePlanarScaler(
- dst_subrect.size(),
- gfx::Rect(0, 0,
- (dst_subrect.width() + 3) & ~3,
- dst_subrect.height()),
- gfx::Size((dst_subrect.width() + 3) / 4,
- dst_subrect.height()),
- false,
- kRGBtoYColorWeights)),
- u_(context, scaler_impl->CreatePlanarScaler(
- dst_subrect.size(),
- gfx::Rect(0, 0,
- (dst_subrect.width() + 7) & ~7,
- (dst_subrect.height() + 1) & ~1),
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2),
- false,
- kRGBtoUColorWeights)),
- v_(context, scaler_impl->CreatePlanarScaler(
- dst_subrect.size(),
- gfx::Rect(0, 0,
- (dst_subrect.width() + 7) & ~7,
- (dst_subrect.height() + 1) & ~1),
- gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2),
- false,
- kRGBtoVColorWeights)) {
+ swizzle_(swizzle),
+ scaler_(gl,
+ scaler_impl->CreateScaler(quality,
+ src_size,
+ src_subrect,
+ dst_subrect.size(),
+ flip_vertically,
+ false)),
+ y_(gl,
+ scaler_impl->CreatePlanarScaler(
+ dst_subrect.size(),
+ gfx::Rect(0,
+ 0,
+ (dst_subrect.width() + 3) & ~3,
+ dst_subrect.height()),
+ gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
+ false,
+ (swizzle == kSwizzleBGRA),
+ kRGBtoYColorWeights)),
+ u_(gl,
+ scaler_impl->CreatePlanarScaler(
+ dst_subrect.size(),
+ gfx::Rect(0,
+ 0,
+ (dst_subrect.width() + 7) & ~7,
+ (dst_subrect.height() + 1) & ~1),
+ gfx::Size((dst_subrect.width() + 7) / 8,
+ (dst_subrect.height() + 1) / 2),
+ false,
+ (swizzle == kSwizzleBGRA),
+ kRGBtoUColorWeights)),
+ v_(gl,
+ scaler_impl->CreatePlanarScaler(
+ dst_subrect.size(),
+ gfx::Rect(0,
+ 0,
+ (dst_subrect.width() + 7) & ~7,
+ (dst_subrect.height() + 1) & ~1),
+ 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));
DCHECK(!(dst_subrect.width() & 1));
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback) {
- WebGLId mailbox_texture =
+ GLuint mailbox_texture =
copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
// Scale texture to right size.
scaler_.Scale(mailbox_texture);
- context_->deleteTexture(mailbox_texture);
+ gl_->DeleteTextures(1, &mailbox_texture);
// Convert the scaled texture in to Y, U and V planes.
y_.Scale(scaler_.texture());
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(),
- target,
- media::VideoFrame::kVPlane,
- 1,
- dst_subrect_,
- base::Bind(&CallbackKeepingVideoFrameAlive,
- target,
- callback));
- context_->bindFramebuffer(GL_FRAMEBUFFER, 0);
- media::LetterboxYUV(target, dst_subrect_);
+ copy_impl_->ReadbackPlane(
+ v_.texture_and_framebuffer(),
+ target,
+ media::VideoFrame::kVPlane,
+ 1,
+ dst_subrect_,
+ swizzle_,
+ base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ media::LetterboxYUV(target.get(), dst_subrect_);
}
// YUV readback constructors. Initiates the main scaler pipeline and
// one planar scaler for each of the Y, U and V planes.
GLHelper::CopyTextureToImpl::ReadbackYUV_MRT::ReadbackYUV_MRT(
- WebGraphicsContext3D* context,
+ GLES2Interface* gl,
CopyTextureToImpl* copy_impl,
GLHelperScaling* scaler_impl,
GLHelper::ScalerQuality quality,
const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Rect& dst_subrect,
- bool flip_vertically)
- : context_(context),
+ bool flip_vertically,
+ ReadbackSwizzle swizzle)
+ : gl_(gl),
copy_impl_(copy_impl),
dst_size_(dst_size),
dst_subrect_(dst_subrect),
quality_(quality),
- scaler_(context, scaler_impl->CreateScaler(
- quality,
- src_size,
- src_subrect,
- dst_subrect.size(),
- false,
- false)),
+ swizzle_(swizzle),
+ scaler_(gl,
+ scaler_impl->CreateScaler(quality,
+ src_size,
+ src_subrect,
+ dst_subrect.size(),
+ false,
+ false)),
pass1_shader_(scaler_impl->CreateYuvMrtShader(
dst_subrect.size(),
- gfx::Rect(0, 0,
- (dst_subrect.width() + 3) & ~3,
- dst_subrect.height()),
- gfx::Size((dst_subrect.width() + 3) / 4,
- dst_subrect.height()),
+ 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::Rect(0, 0,
+ gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height()),
+ gfx::Rect(0,
+ 0,
(dst_subrect.width() + 7) / 8 * 2,
dst_subrect.height()),
gfx::Size((dst_subrect.width() + 7) / 8,
(dst_subrect.height() + 1) / 2),
false,
+ (swizzle == kSwizzleBGRA),
GLHelperScaling::SHADER_YUV_MRT_PASS2)),
- y_(context, gfx::Size((dst_subrect.width() + 3) / 4,
- dst_subrect.height())),
- uv_(context, context->createTexture()),
- u_(context, gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2)),
- v_(context, gfx::Size((dst_subrect.width() + 7) / 8,
- (dst_subrect.height() + 1) / 2)) {
-
- content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context, uv_);
- context->texImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- (dst_subrect.width() + 3) / 4,
- dst_subrect.height(),
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- NULL);
+ y_(gl, gfx::Size((dst_subrect.width() + 3) / 4, dst_subrect.height())),
+ uv_(gl),
+ u_(gl,
+ gfx::Size((dst_subrect.width() + 7) / 8,
+ (dst_subrect.height() + 1) / 2)),
+ v_(gl,
+ gfx::Size((dst_subrect.width() + 7) / 8,
+ (dst_subrect.height() + 1) / 2)) {
+
+ content::ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl, uv_);
+ gl->TexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ (dst_subrect.width() + 3) / 4,
+ dst_subrect.height(),
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ NULL);
DCHECK(!(dst_size.width() & 1));
DCHECK(!(dst_size.height() & 1));
uint32 sync_point,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback) {
- WebGLId mailbox_texture =
+ GLuint mailbox_texture =
copy_impl_->ConsumeMailboxToTexture(mailbox, sync_point);
- WebGLId texture;
+ GLuint texture;
if (quality_ == GLHelper::SCALER_QUALITY_FAST) {
// Optimization: SCALER_QUALITY_FAST is just a single bilinear
// pass, which pass1_shader_ can do just as well, so let's skip
texture = scaler_.texture();
}
-
- std::vector<WebKit::WebGLId> outputs(2);
+ std::vector<GLuint> outputs(2);
// Convert the scaled texture in to Y, U and V planes.
outputs[0] = y_.texture();
outputs[1] = uv_;
pass1_shader_->Execute(texture, outputs);
- context_->deleteTexture(mailbox_texture);
+ gl_->DeleteTextures(1, &mailbox_texture);
outputs[0] = u_.texture();
outputs[1] = v_.texture();
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_,
- target,
- media::VideoFrame::kVPlane,
- 1,
- dst_subrect_,
- base::Bind(&CallbackKeepingVideoFrameAlive,
- target,
- callback));
- context_->bindFramebuffer(GL_FRAMEBUFFER, 0);
- media::LetterboxYUV(target, dst_subrect_);
+ copy_impl_->ReadbackPlane(
+ &v_,
+ target,
+ media::VideoFrame::kVPlane,
+ 1,
+ dst_subrect_,
+ swizzle_,
+ base::Bind(&CallbackKeepingVideoFrameAlive, target, callback));
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
+ media::LetterboxYUV(target.get(), dst_subrect_);
}
-ReadbackYUVInterface*
-GLHelper::CopyTextureToImpl::CreateReadbackPipelineYUV(
+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(
GLHelper::ScalerQuality quality,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
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(
- context_,
- this,
- helper_->scaler_impl_.get(),
- quality,
- src_size,
- src_subrect,
- dst_size,
- dst_subrect,
- flip_vertically);
+ return new ReadbackYUV_MRT(gl_,
+ this,
+ helper_->scaler_impl_.get(),
+ quality,
+ src_size,
+ src_subrect,
+ dst_size,
+ dst_subrect,
+ flip_vertically,
+ swizzle);
}
- return new ReadbackYUVImpl(
- context_,
- this,
- helper_->scaler_impl_.get(),
- quality,
- src_size,
- src_subrect,
- dst_size,
- dst_subrect,
- flip_vertically);
+ return new ReadbackYUVImpl(gl_,
+ this,
+ helper_->scaler_impl_.get(),
+ quality,
+ src_size,
+ src_subrect,
+ dst_size,
+ dst_subrect,
+ flip_vertically,
+ swizzle);
}
-ReadbackYUVInterface*
-GLHelper::CreateReadbackPipelineYUV(
+ReadbackYUVInterface* GLHelper::CreateReadbackPipelineYUV(
ScalerQuality quality,
const gfx::Size& src_size,
const gfx::Rect& src_subrect,
bool flip_vertically,
bool use_mrt) {
InitCopyTextToImpl();
- return copy_texture_to_impl_->CreateReadbackPipelineYUV(
- quality,
- src_size,
- src_subrect,
- dst_size,
- dst_subrect,
- flip_vertically,
- use_mrt);
+ return copy_texture_to_impl_->CreateReadbackPipelineYUV(quality,
+ src_size,
+ src_subrect,
+ dst_size,
+ dst_subrect,
+ flip_vertically,
+ use_mrt);
}
} // namespace content