Chromium Code Reviews| Index: ui/gl/gl_image_memory.cc |
| diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc |
| index 045c50c464fa143353938887763329af87e22911..7df7dbc64bacd73a992e6c59cce7a00a3937ec24 100644 |
| --- a/ui/gl/gl_image_memory.cc |
| +++ b/ui/gl/gl_image_memory.cc |
| @@ -6,6 +6,7 @@ |
| #include "base/logging.h" |
| #include "base/trace_event/trace_event.h" |
| +#include "ui/gfx/buffer_format_util.h" |
| #include "ui/gl/gl_bindings.h" |
| namespace gfx { |
| @@ -19,6 +20,7 @@ bool ValidInternalFormat(unsigned internalformat) { |
| case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
| case GL_ETC1_RGB8_OES: |
| case GL_R8: |
| + case GL_RGB: |
| case GL_RGBA: |
| case GL_BGRA_EXT: |
| return true; |
| @@ -36,10 +38,11 @@ bool ValidFormat(BufferFormat format) { |
| case BufferFormat::ETC1: |
| case BufferFormat::R_8: |
| case BufferFormat::RGBA_4444: |
| + case BufferFormat::RGBX_8888: |
| case BufferFormat::RGBA_8888: |
| + case BufferFormat::BGRX_8888: |
| case BufferFormat::BGRA_8888: |
| return true; |
| - case BufferFormat::BGRX_8888: |
| case BufferFormat::YUV_420: |
| case BufferFormat::YUV_420_BIPLANAR: |
| case BufferFormat::UYVY_422: |
| @@ -60,9 +63,10 @@ bool IsCompressedFormat(BufferFormat format) { |
| return true; |
| case BufferFormat::R_8: |
| case BufferFormat::RGBA_4444: |
| + case BufferFormat::RGBX_8888: |
| case BufferFormat::RGBA_8888: |
| - case BufferFormat::BGRA_8888: |
| case BufferFormat::BGRX_8888: |
| + case BufferFormat::BGRA_8888: |
| case BufferFormat::YUV_420: |
| case BufferFormat::YUV_420_BIPLANAR: |
| case BufferFormat::UYVY_422: |
| @@ -92,7 +96,9 @@ GLenum TextureFormat(BufferFormat format) { |
| return GL_RGBA; |
| case BufferFormat::BGRA_8888: |
| return GL_BGRA_EXT; |
| + case BufferFormat::RGBX_8888: |
| case BufferFormat::BGRX_8888: |
| + return GL_RGB; |
| case BufferFormat::YUV_420: |
| case BufferFormat::YUV_420_BIPLANAR: |
| case BufferFormat::UYVY_422: |
| @@ -105,7 +111,28 @@ GLenum TextureFormat(BufferFormat format) { |
| } |
| GLenum DataFormat(BufferFormat format) { |
| - return TextureFormat(format); |
| + switch (format) { |
| + case BufferFormat::RGBX_8888: |
| + return GL_RGBA; |
| + case BufferFormat::BGRX_8888: |
| + return GL_BGRA_EXT; |
| + case BufferFormat::RGBA_4444: |
| + case BufferFormat::RGBA_8888: |
| + case BufferFormat::BGRA_8888: |
| + case BufferFormat::R_8: |
| + case BufferFormat::ATC: |
| + case BufferFormat::ATCIA: |
| + case BufferFormat::DXT1: |
| + case BufferFormat::DXT5: |
| + case BufferFormat::ETC1: |
| + case BufferFormat::YUV_420: |
| + case BufferFormat::YUV_420_BIPLANAR: |
| + case BufferFormat::UYVY_422: |
| + return TextureFormat(format); |
| + } |
| + |
| + NOTREACHED(); |
| + return 0; |
| } |
| GLenum DataType(BufferFormat format) { |
| @@ -116,12 +143,15 @@ GLenum DataType(BufferFormat format) { |
| case BufferFormat::BGRA_8888: |
| case BufferFormat::R_8: |
| return GL_UNSIGNED_BYTE; |
| + case BufferFormat::RGBX_8888: |
| + return GL_UNSIGNED_INT_8_8_8_8; |
| + case BufferFormat::BGRX_8888: |
| + return GL_UNSIGNED_INT_8_8_8_8_REV; |
|
piman
2015/10/23 00:52:44
Hmm, I'm not sure what the expectation is here. Th
reveman
2015/10/23 13:44:43
Yea, that made no sense. Thanks for noticing. Late
|
| case BufferFormat::ATC: |
| case BufferFormat::ATCIA: |
| case BufferFormat::DXT1: |
| case BufferFormat::DXT5: |
| case BufferFormat::ETC1: |
| - case BufferFormat::BGRX_8888: |
| case BufferFormat::YUV_420: |
| case BufferFormat::YUV_420_BIPLANAR: |
| case BufferFormat::UYVY_422: |
| @@ -133,71 +163,85 @@ GLenum DataType(BufferFormat format) { |
| return 0; |
| } |
| -GLsizei SizeInBytes(const Size& size, BufferFormat format) { |
| - size_t stride_in_bytes = 0; |
| - bool valid_stride = GLImageMemory::StrideInBytes( |
| - size.width(), format, &stride_in_bytes); |
| - DCHECK(valid_stride); |
| - return static_cast<GLsizei>(stride_in_bytes * size.height()); |
| -} |
| - |
| -} // namespace |
| - |
| -GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) |
| - : size_(size), |
| - internalformat_(internalformat), |
| - memory_(nullptr), |
| - format_(BufferFormat::RGBA_8888) {} |
| +template <typename F> |
| +scoped_ptr<uint8_t[]> GLES2RGBData(const Size& size, |
| + BufferFormat format, |
| + const uint8_t* data, |
| + F const& data_to_rgb, |
| + GLenum* data_format, |
| + GLenum* data_type) { |
| + TRACE_EVENT2("gpu", "GLES2RGBData", "width", size.width(), "height", |
| + size.height()); |
| + |
| + // Four-byte row alignment as specified by glPixelStorei with argument |
| + // GL_UNPACK_ALIGNMENT set to 4. |
| + size_t gles2_rgb_data_stride = (size.width() * 3 + 3) & ~3; |
| + scoped_ptr<uint8_t[]> gles2_rgb_data( |
| + new uint8_t[gles2_rgb_data_stride * size.height()]); |
| + size_t data_stride = RowSizeForBufferFormat(size.width(), format, 0); |
| + |
| + for (int y = 0; y < size.height(); ++y) { |
| + for (int x = 0; x < size.width(); ++x) { |
| + data_to_rgb(&data[y * data_stride + x * 4], |
| + &gles2_rgb_data[y * gles2_rgb_data_stride + x * 3]); |
| + } |
| + } |
| -GLImageMemory::~GLImageMemory() { |
| - DCHECK(!memory_); |
| + *data_format = GL_RGB; |
| + *data_type = GL_UNSIGNED_BYTE; |
| + return gles2_rgb_data.Pass(); |
| } |
| -// static |
| -bool GLImageMemory::StrideInBytes(size_t width, |
| - BufferFormat format, |
| - size_t* stride_in_bytes) { |
| - base::CheckedNumeric<size_t> checked_stride = width; |
| +scoped_ptr<uint8_t[]> GLES2Data(const Size& size, |
| + BufferFormat format, |
| + const uint8_t* data, |
| + GLenum* data_format, |
| + GLenum* data_type) { |
| switch (format) { |
| - case BufferFormat::ATCIA: |
| - case BufferFormat::DXT5: |
| - *stride_in_bytes = width; |
| - return true; |
| - case BufferFormat::ATC: |
| - case BufferFormat::DXT1: |
| - case BufferFormat::ETC1: |
| - DCHECK_EQ(width % 2, 0u); |
| - *stride_in_bytes = width / 2; |
| - return true; |
| - case BufferFormat::R_8: |
| - checked_stride += 3; |
| - if (!checked_stride.IsValid()) |
| - return false; |
| - *stride_in_bytes = checked_stride.ValueOrDie() & ~0x3; |
| - return true; |
| + case BufferFormat::RGBX_8888: |
| + return GLES2RGBData(size, format, |
| + data, [](const uint8_t* src, uint8_t* dst) { |
| + dst[0] = src[0]; |
| + dst[1] = src[1]; |
| + dst[2] = src[2]; |
| + }, data_format, data_type); |
| + case BufferFormat::BGRX_8888: |
| + return GLES2RGBData(size, format, |
| + data, [](const uint8_t* src, uint8_t* dst) { |
| + dst[0] = src[2]; |
| + dst[1] = src[1]; |
| + dst[2] = src[0]; |
| + }, data_format, data_type); |
| case BufferFormat::RGBA_4444: |
| - checked_stride *= 2; |
| - if (!checked_stride.IsValid()) |
| - return false; |
| - *stride_in_bytes = checked_stride.ValueOrDie(); |
| - return true; |
| case BufferFormat::RGBA_8888: |
| case BufferFormat::BGRA_8888: |
| - checked_stride *= 4; |
| - if (!checked_stride.IsValid()) |
| - return false; |
| - *stride_in_bytes = checked_stride.ValueOrDie(); |
| - return true; |
| - case BufferFormat::BGRX_8888: |
| + case BufferFormat::R_8: |
| + case BufferFormat::ATC: |
| + case BufferFormat::ATCIA: |
| + case BufferFormat::DXT1: |
| + case BufferFormat::DXT5: |
| + case BufferFormat::ETC1: |
| case BufferFormat::YUV_420: |
| case BufferFormat::YUV_420_BIPLANAR: |
| case BufferFormat::UYVY_422: |
| - NOTREACHED(); |
| - return false; |
| + // No data conversion needed. |
| + return nullptr; |
| } |
| NOTREACHED(); |
| - return false; |
| + return 0; |
| +} |
| + |
| +} // namespace |
| + |
| +GLImageMemory::GLImageMemory(const Size& size, unsigned internalformat) |
| + : size_(size), |
| + internalformat_(internalformat), |
| + memory_(nullptr), |
| + format_(BufferFormat::RGBA_8888) {} |
| + |
| +GLImageMemory::~GLImageMemory() { |
| + DCHECK(!memory_); |
| } |
| bool GLImageMemory::Initialize(const unsigned char* memory, |
| @@ -247,12 +291,20 @@ bool GLImageMemory::CopyTexImage(unsigned target) { |
| if (IsCompressedFormat(format_)) { |
| glCompressedTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
| - size_.height(), 0, SizeInBytes(size_, format_), |
| - memory_); |
| + size_.height(), 0, |
| + BufferSizeForBufferFormat(size_, format_), memory_); |
| } else { |
| + GLenum data_format = DataFormat(format_); |
| + GLenum data_type = DataType(format_); |
| + // Note: Conversion of data to a GLES2 supported format is not necessary |
| + // when using full OpenGL and additional data types are available. To keep |
| + // things simple, always convert to GLES2 supported format for now. |
| + scoped_ptr<uint8_t[]> gles2_data = |
| + GLES2Data(size_, format_, memory_, &data_format, &data_type); |
| + |
| glTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
| - size_.height(), 0, DataFormat(format_), DataType(format_), |
| - memory_); |
| + size_.height(), 0, data_format, data_type, |
| + gles2_data ? gles2_data.get() : memory_); |
| } |
| return true; |
| @@ -276,19 +328,22 @@ bool GLImageMemory::CopyTexSubImage(unsigned target, |
| if (IsCompressedFormat(format_) && rect.height() % 4) |
| return false; |
| - size_t stride_in_bytes = 0; |
| - bool rv = StrideInBytes(size_.width(), format_, &stride_in_bytes); |
| - DCHECK(rv); |
| - DCHECK(memory_); |
| - const unsigned char* data = memory_ + rect.y() * stride_in_bytes; |
| + const uint8_t* data = |
| + memory_ + rect.y() * RowSizeForBufferFormat(size_.width(), format_, 0); |
| if (IsCompressedFormat(format_)) { |
| glCompressedTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
| rect.height(), DataFormat(format_), |
| - SizeInBytes(rect.size(), format_), data); |
| + BufferSizeForBufferFormat(rect.size(), format_), |
| + data); |
| } else { |
| + GLenum data_format = DataFormat(format_); |
| + GLenum data_type = DataType(format_); |
| + scoped_ptr<uint8_t[]> gles2_data = |
| + GLES2Data(rect.size(), format_, data, &data_format, &data_type); |
| + |
| glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
| - rect.height(), DataFormat(format_), DataType(format_), |
| - data); |
| + rect.height(), data_format, data_type, |
| + gles2_data ? gles2_data.get() : data); |
| } |
| return true; |
| @@ -302,4 +357,10 @@ bool GLImageMemory::ScheduleOverlayPlane(AcceleratedWidget widget, |
| return false; |
| } |
| +// static |
| +unsigned GLImageMemory::GetInternalFormatForTesting(BufferFormat format) { |
| + DCHECK(ValidFormat(format)); |
| + return TextureFormat(format); |
| +} |
| + |
| } // namespace gfx |