Index: ui/gl/gl_image_memory.cc |
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc |
index 03391ba2a60493cc964ca83c0c4aff89b1aebcb2..3bdf596144679c517ce8e9e2dcd9abc636ddbef7 100644 |
--- a/ui/gl/gl_image_memory.cc |
+++ b/ui/gl/gl_image_memory.cc |
@@ -5,6 +5,7 @@ |
#include "ui/gl/gl_image_memory.h" |
#include "base/logging.h" |
+#include "base/numerics/safe_conversions.h" |
#include "base/trace_event/trace_event.h" |
#include "ui/gfx/buffer_format_util.h" |
#include "ui/gl/gl_bindings.h" |
@@ -71,9 +72,11 @@ bool IsCompressedFormat(BufferFormat format) { |
case BufferFormat::RGBA_8888: |
case BufferFormat::BGRX_8888: |
case BufferFormat::BGRA_8888: |
+ return false; |
case BufferFormat::YUV_420: |
case BufferFormat::YUV_420_BIPLANAR: |
case BufferFormat::UYVY_422: |
+ NOTREACHED(); |
return false; |
} |
@@ -129,10 +132,12 @@ GLenum DataFormat(BufferFormat format) { |
case BufferFormat::DXT1: |
case BufferFormat::DXT5: |
case BufferFormat::ETC1: |
+ return TextureFormat(format); |
case BufferFormat::YUV_420: |
case BufferFormat::YUV_420_BIPLANAR: |
case BufferFormat::UYVY_422: |
- return TextureFormat(format); |
+ NOTREACHED(); |
+ return 0; |
} |
NOTREACHED(); |
@@ -165,13 +170,42 @@ GLenum DataType(BufferFormat format) { |
return 0; |
} |
+GLint DataRowLength(size_t stride, BufferFormat format) { |
+ switch (format) { |
+ case BufferFormat::RGBA_4444: |
+ return base::checked_cast<GLint>(stride) / 2; |
+ case BufferFormat::RGBX_8888: |
+ case BufferFormat::RGBA_8888: |
+ case BufferFormat::BGRX_8888: |
+ case BufferFormat::BGRA_8888: |
+ return base::checked_cast<GLint>(stride) / 4; |
+ case BufferFormat::R_8: |
+ return base::checked_cast<GLint>(stride); |
+ 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 0; |
+ } |
+ |
+ NOTREACHED(); |
+ return 0; |
+} |
+ |
template <typename F> |
scoped_ptr<uint8_t[]> GLES2RGBData(const gfx::Size& size, |
BufferFormat format, |
+ size_t stride, |
const uint8_t* data, |
F const& data_to_rgb, |
GLenum* data_format, |
- GLenum* data_type) { |
+ GLenum* data_type, |
+ GLint* data_row_length) { |
TRACE_EVENT2("gpu", "GLES2RGBData", "width", size.width(), "height", |
size.height()); |
@@ -180,58 +214,78 @@ scoped_ptr<uint8_t[]> GLES2RGBData(const gfx::Size& size, |
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], |
+ data_to_rgb(&data[y * stride + x * 4], |
&gles2_rgb_data[y * gles2_rgb_data_stride + x * 3]); |
} |
} |
*data_format = GL_RGB; |
*data_type = GL_UNSIGNED_BYTE; |
+ *data_row_length = size.width(); |
return gles2_rgb_data.Pass(); |
} |
scoped_ptr<uint8_t[]> GLES2Data(const gfx::Size& size, |
BufferFormat format, |
+ size_t stride, |
const uint8_t* data, |
GLenum* data_format, |
- GLenum* data_type) { |
+ GLenum* data_type, |
+ GLint* data_row_length) { |
+ TRACE_EVENT2("gpu", "GLES2Data", "width", size.width(), "height", |
+ size.height()); |
+ |
switch (format) { |
case BufferFormat::RGBX_8888: |
- return GLES2RGBData(size, format, |
+ return GLES2RGBData(size, format, stride, |
data, [](const uint8_t* src, uint8_t* dst) { |
dst[0] = src[0]; |
dst[1] = src[1]; |
dst[2] = src[2]; |
- }, data_format, data_type); |
+ }, data_format, data_type, data_row_length); |
case BufferFormat::BGRX_8888: |
- return GLES2RGBData(size, format, |
+ return GLES2RGBData(size, format, stride, |
data, [](const uint8_t* src, uint8_t* dst) { |
dst[0] = src[2]; |
dst[1] = src[1]; |
dst[2] = src[0]; |
- }, data_format, data_type); |
+ }, data_format, data_type, data_row_length); |
case BufferFormat::RGBA_4444: |
case BufferFormat::RGBA_8888: |
case BufferFormat::BGRA_8888: |
- case BufferFormat::R_8: |
+ case BufferFormat::R_8: { |
+ size_t gles2_data_stride = |
+ RowSizeForBufferFormat(size.width(), format, 0); |
+ if (stride == gles2_data_stride) |
+ return nullptr; // No data conversion needed |
+ |
+ scoped_ptr<uint8_t[]> gles2_data( |
+ new uint8_t[gles2_data_stride * size.height()]); |
+ for (int y = 0; y < size.height(); ++y) { |
+ memcpy(&gles2_data[y * gles2_data_stride], &data[y * stride], |
+ gles2_data_stride); |
+ } |
+ *data_row_length = size.width(); |
+ return gles2_data.Pass(); |
+ } |
case BufferFormat::ATC: |
case BufferFormat::ATCIA: |
case BufferFormat::DXT1: |
case BufferFormat::DXT5: |
case BufferFormat::ETC1: |
+ return nullptr; // No data conversion needed |
case BufferFormat::YUV_420: |
case BufferFormat::YUV_420_BIPLANAR: |
case BufferFormat::UYVY_422: |
- // No data conversion needed. |
+ NOTREACHED(); |
return nullptr; |
} |
NOTREACHED(); |
- return 0; |
+ return nullptr; |
} |
} // namespace |
@@ -240,14 +294,16 @@ GLImageMemory::GLImageMemory(const gfx::Size& size, unsigned internalformat) |
: size_(size), |
internalformat_(internalformat), |
memory_(nullptr), |
- format_(BufferFormat::RGBA_8888) {} |
+ format_(BufferFormat::RGBA_8888), |
+ stride_(0) {} |
GLImageMemory::~GLImageMemory() { |
DCHECK(!memory_); |
} |
bool GLImageMemory::Initialize(const unsigned char* memory, |
- BufferFormat format) { |
+ BufferFormat format, |
+ size_t stride) { |
if (!ValidInternalFormat(internalformat_)) { |
LOG(ERROR) << "Invalid internalformat: " << internalformat_; |
return false; |
@@ -258,12 +314,18 @@ bool GLImageMemory::Initialize(const unsigned char* memory, |
return false; |
} |
+ if (stride < RowSizeForBufferFormat(size_.width(), format, 0) || stride & 3) { |
+ LOG(ERROR) << "Invalid stride: " << stride; |
+ return false; |
+ } |
+ |
DCHECK(memory); |
DCHECK(!memory_); |
DCHECK(!IsCompressedFormat(format) || size_.width() % 4 == 0); |
DCHECK(!IsCompressedFormat(format) || size_.height() % 4 == 0); |
memory_ = memory; |
format_ = format; |
+ stride_ = stride; |
return true; |
} |
@@ -297,16 +359,25 @@ bool GLImageMemory::CopyTexImage(unsigned target) { |
static_cast<GLsizei>(BufferSizeForBufferFormat(size_, format_)), |
memory_); |
} else { |
- scoped_ptr<uint8_t[]> gles2_data; |
GLenum data_format = DataFormat(format_); |
GLenum data_type = DataType(format_); |
+ GLint data_row_length = DataRowLength(stride_, format_); |
+ scoped_ptr<uint8_t[]> gles2_data; |
+ |
+ if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) { |
+ gles2_data = GLES2Data(size_, format_, stride_, memory_, &data_format, |
+ &data_type, &data_row_length); |
+ } |
- if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) |
- gles2_data = GLES2Data(size_, format_, memory_, &data_format, &data_type); |
+ if (data_row_length != size_.width()) |
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length); |
glTexImage2D(target, 0, TextureFormat(format_), size_.width(), |
size_.height(), 0, data_format, data_type, |
gles2_data ? gles2_data.get() : memory_); |
+ |
+ if (data_row_length != size_.width()) |
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
} |
return true; |
@@ -326,13 +397,12 @@ bool GLImageMemory::CopyTexSubImage(unsigned target, |
if (rect.width() != size_.width()) |
return false; |
- // Height must be a multiple of 4 if compressed. |
- if (IsCompressedFormat(format_) && rect.height() % 4) |
- return false; |
- |
- const uint8_t* data = |
- memory_ + rect.y() * RowSizeForBufferFormat(size_.width(), format_, 0); |
+ const uint8_t* data = memory_ + rect.y() * stride_; |
if (IsCompressedFormat(format_)) { |
+ // Height must be a multiple of 4. |
+ if (rect.height() % 4) |
+ return false; |
+ |
glCompressedTexSubImage2D( |
target, 0, offset.x(), offset.y(), rect.width(), rect.height(), |
DataFormat(format_), |
@@ -341,16 +411,23 @@ bool GLImageMemory::CopyTexSubImage(unsigned target, |
} else { |
GLenum data_format = DataFormat(format_); |
GLenum data_type = DataType(format_); |
+ GLint data_row_length = DataRowLength(stride_, format_); |
scoped_ptr<uint8_t[]> gles2_data; |
if (gfx::GLContext::GetCurrent()->GetVersionInfo()->is_es) { |
- gles2_data = |
- GLES2Data(rect.size(), format_, data, &data_format, &data_type); |
+ gles2_data = GLES2Data(rect.size(), format_, stride_, data, &data_format, |
+ &data_type, &data_row_length); |
} |
+ if (data_row_length != rect.width()) |
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length); |
+ |
glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(), |
rect.height(), data_format, data_type, |
gles2_data ? gles2_data.get() : data); |
+ |
+ if (data_row_length != rect.width()) |
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); |
} |
return true; |