summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreveman <reveman@chromium.org>2015-11-10 10:12:52 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-10 18:13:31 +0000
commitf2322f7fb01ba0dc954c94f48bb5e9a9a41c32e2 (patch)
tree660bc2b43446109c3235cd83aa90b21c095fb823
parent76c1cfc82d78fc8eb503ba300021a816d39538d5 (diff)
downloadchromium_src-f2322f7fb01ba0dc954c94f48bb5e9a9a41c32e2.zip
chromium_src-f2322f7fb01ba0dc954c94f48bb5e9a9a41c32e2.tar.gz
chromium_src-f2322f7fb01ba0dc954c94f48bb5e9a9a41c32e2.tar.bz2
Re-land: ui: Add custom stride support to GLImageMemory.
This improves our support for shared memory pools by allowing clients to create GLImages with a stride that is larger than the row length of the image. This makes it possible to import a buffer with a stride that doesn't match the aligned row size. However, support for mapping of such a buffer is not provided by this patch. BUG=549781 TEST=gl_unittests --gtest_filter=GLImageSharedMemoryPool/GLImageCopyTest/0.CopyTexImage CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel Review URL: https://codereview.chromium.org/1403283007 Cr-Commit-Position: refs/heads/master@{#358850}
-rw-r--r--cc/test/test_gpu_memory_buffer_manager.cc15
-rw-r--r--cc/test/test_image_factory.cc4
-rw-r--r--components/mus/gles2/command_buffer_driver.cc5
-rw-r--r--components/mus/gles2/command_buffer_local.cc5
-rw-r--r--components/mus/gles2/mojo_gpu_memory_buffer.cc1
-rw-r--r--content/browser/gpu/browser_gpu_memory_buffer_manager.cc1
-rw-r--r--content/common/child_process_messages.h1
-rw-r--r--content/common/gpu/client/gpu_channel_host.cc1
-rw-r--r--content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc16
-rw-r--r--content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h4
-rw-r--r--content/common/gpu/gpu_channel.cc7
-rw-r--r--gpu/command_buffer/service/in_process_command_buffer.cc9
-rw-r--r--ui/gfx/gpu_memory_buffer.h1
-rw-r--r--ui/gl/gl_image_memory.cc127
-rw-r--r--ui/gl/gl_image_memory.h6
-rw-r--r--ui/gl/gl_image_ref_counted_memory.cc6
-rw-r--r--ui/gl/gl_image_shared_memory.cc22
-rw-r--r--ui/gl/gl_image_shared_memory.h3
-rw-r--r--ui/gl/gl_image_shared_memory_unittest.cc18
19 files changed, 193 insertions, 59 deletions
diff --git a/cc/test/test_gpu_memory_buffer_manager.cc b/cc/test/test_gpu_memory_buffer_manager.cc
index ed5e713..af86cbb 100644
--- a/cc/test/test_gpu_memory_buffer_manager.cc
+++ b/cc/test/test_gpu_memory_buffer_manager.cc
@@ -17,16 +17,19 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
GpuMemoryBufferImpl(const gfx::Size& size,
gfx::BufferFormat format,
scoped_ptr<base::SharedMemory> shared_memory,
- size_t offset)
+ size_t offset,
+ size_t stride)
: size_(size),
format_(format),
shared_memory_(shared_memory.Pass()),
offset_(offset),
+ stride_(stride),
mapped_(false) {}
// Overridden from gfx::GpuMemoryBuffer:
bool Map() override {
DCHECK(!mapped_);
+ DCHECK_EQ(stride_, gfx::RowSizeForBufferFormat(size_.width(), format_, 0));
if (!shared_memory_->Map(offset_ +
gfx::BufferSizeForBufferFormat(size_, format_)))
return false;
@@ -60,6 +63,7 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.handle = shared_memory_->handle();
handle.offset = base::checked_cast<uint32_t>(offset_);
+ handle.stride = base::checked_cast<int32_t>(stride_);
return handle;
}
ClientBuffer AsClientBuffer() override {
@@ -71,6 +75,7 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
gfx::BufferFormat format_;
scoped_ptr<base::SharedMemory> shared_memory_;
size_t offset_;
+ size_t stride_;
bool mapped_;
};
@@ -90,8 +95,10 @@ TestGpuMemoryBufferManager::AllocateGpuMemoryBuffer(const gfx::Size& size,
const size_t buffer_size = gfx::BufferSizeForBufferFormat(size, format);
if (!shared_memory->CreateAnonymous(buffer_size))
return nullptr;
- return make_scoped_ptr<gfx::GpuMemoryBuffer>(
- new GpuMemoryBufferImpl(size, format, shared_memory.Pass(), 0));
+ return make_scoped_ptr<gfx::GpuMemoryBuffer>(new GpuMemoryBufferImpl(
+ size, format, shared_memory.Pass(), 0,
+ base::checked_cast<int>(
+ gfx::RowSizeForBufferFormat(size.width(), format, 0))));
}
scoped_ptr<gfx::GpuMemoryBuffer>
@@ -105,7 +112,7 @@ TestGpuMemoryBufferManager::CreateGpuMemoryBufferFromHandle(
return make_scoped_ptr<gfx::GpuMemoryBuffer>(new GpuMemoryBufferImpl(
size, format,
make_scoped_ptr(new base::SharedMemory(handle.handle, false)),
- handle.offset));
+ handle.offset, handle.stride));
}
gfx::GpuMemoryBuffer*
diff --git a/cc/test/test_image_factory.cc b/cc/test/test_image_factory.cc
index 69070e7..79c2e7e 100644
--- a/cc/test/test_image_factory.cc
+++ b/cc/test/test_image_factory.cc
@@ -4,6 +4,7 @@
#include "cc/test/test_image_factory.h"
+#include "base/numerics/safe_conversions.h"
#include "ui/gl/gl_image_shared_memory.h"
namespace cc {
@@ -24,7 +25,8 @@ scoped_refptr<gl::GLImage> TestImageFactory::CreateImageForGpuMemoryBuffer(
scoped_refptr<gl::GLImageSharedMemory> image(
new gl::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle.handle, handle.id, format, handle.offset))
+ if (!image->Initialize(handle.handle, handle.id, format, handle.offset,
+ base::checked_cast<size_t>(handle.stride)))
return nullptr;
return image;
diff --git a/components/mus/gles2/command_buffer_driver.cc b/components/mus/gles2/command_buffer_driver.cc
index ba13464..2a7265a 100644
--- a/components/mus/gles2/command_buffer_driver.cc
+++ b/components/mus/gles2/command_buffer_driver.cc
@@ -26,6 +26,7 @@
#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "mojo/converters/geometry/geometry_type_converters.h"
#include "mojo/platform_handle/platform_handle_functions.h"
+#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/gl_context.h"
@@ -250,7 +251,9 @@ void CommandBufferDriver::CreateImage(int32_t id,
scoped_refptr<gl::GLImageSharedMemory> image =
new gl::GLImageSharedMemory(gfx_size, internal_format);
// TODO(jam): also need a mojo enum for this enum
- if (!image->Initialize(handle, gfx::GpuMemoryBufferId(id), gpu_format, 0)) {
+ if (!image->Initialize(
+ handle, gfx::GpuMemoryBufferId(id), gpu_format, 0,
+ gfx::RowSizeForBufferFormat(gfx_size.width(), gpu_format, 0))) {
NOTREACHED();
return;
}
diff --git a/components/mus/gles2/command_buffer_local.cc b/components/mus/gles2/command_buffer_local.cc
index 2e0535b..461262b 100644
--- a/components/mus/gles2/command_buffer_local.cc
+++ b/components/mus/gles2/command_buffer_local.cc
@@ -18,6 +18,7 @@
#include "gpu/command_buffer/service/shader_translator_cache.h"
#include "gpu/command_buffer/service/transfer_buffer_manager.h"
#include "gpu/command_buffer/service/valuebuffer_manager.h"
+#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_image_shared_memory.h"
@@ -139,7 +140,9 @@ int32_t CommandBufferLocal::CreateImage(ClientBuffer buffer,
gfx::Size(static_cast<int>(width), static_cast<int>(height)),
internalformat));
if (!image->Initialize(base::SharedMemory::DuplicateHandle(handle.handle),
- handle.id, gpu_memory_buffer->GetFormat(), 0)) {
+ handle.id, gpu_memory_buffer->GetFormat(), 0,
+ gfx::RowSizeForBufferFormat(
+ width, gpu_memory_buffer->GetFormat(), 0))) {
return -1;
}
diff --git a/components/mus/gles2/mojo_gpu_memory_buffer.cc b/components/mus/gles2/mojo_gpu_memory_buffer.cc
index dfa7d8b..597cd69 100644
--- a/components/mus/gles2/mojo_gpu_memory_buffer.cc
+++ b/components/mus/gles2/mojo_gpu_memory_buffer.cc
@@ -87,6 +87,7 @@ gfx::GpuMemoryBufferHandle MojoGpuMemoryBufferImpl::GetHandle() const {
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.handle = shared_memory_->handle();
handle.offset = 0;
+ handle.stride = gfx::RowSizeForBufferFormat(size_.width(), format_, 0);
return handle;
}
diff --git a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
index 7a5921a..b4b474e 100644
--- a/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
+++ b/content/browser/gpu/browser_gpu_memory_buffer_manager.cc
@@ -546,6 +546,7 @@ void BrowserGpuMemoryBufferManager::HandleCreateGpuMemoryBufferFromHandleOnIO(
handle.id = new_id;
handle.handle = request->handle.handle;
handle.offset = request->handle.offset;
+ handle.stride = request->handle.stride;
// Note: Unretained is safe as IO thread is stopped before manager is
// destroyed.
diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h
index ec2a4bf..da73059 100644
--- a/content/common/child_process_messages.h
+++ b/content/common/child_process_messages.h
@@ -70,6 +70,7 @@ IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_MEMBER(handle)
IPC_STRUCT_TRAITS_MEMBER(offset)
+ IPC_STRUCT_TRAITS_MEMBER(stride)
#if defined(USE_OZONE)
IPC_STRUCT_TRAITS_MEMBER(native_pixmap_handle)
#endif
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 8ff3ab8..80dfe0a 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -372,6 +372,7 @@ gfx::GpuMemoryBufferHandle GpuChannelHost::ShareGpuMemoryBufferToGpuProcess(
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.handle = ShareToGpuProcess(source_handle.handle);
handle.offset = source_handle.offset;
+ handle.stride = source_handle.stride;
*requires_sync_point = false;
return handle;
}
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
index 9a36a3b..b7f750e 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.cc
@@ -23,10 +23,12 @@ GpuMemoryBufferImplSharedMemory::GpuMemoryBufferImplSharedMemory(
gfx::BufferFormat format,
const DestructionCallback& callback,
scoped_ptr<base::SharedMemory> shared_memory,
- size_t offset)
+ size_t offset,
+ int stride)
: GpuMemoryBufferImpl(id, size, format, callback),
shared_memory_(shared_memory.Pass()),
- offset_(offset) {
+ offset_(offset),
+ stride_(stride) {
DCHECK(IsSizeValidForFormat(size, format));
}
@@ -48,7 +50,8 @@ GpuMemoryBufferImplSharedMemory::Create(gfx::GpuMemoryBufferId id,
return nullptr;
return make_scoped_ptr(new GpuMemoryBufferImplSharedMemory(
- id, size, format, callback, shared_memory.Pass(), 0));
+ id, size, format, callback, shared_memory.Pass(), 0,
+ gfx::RowSizeForBufferFormat(size.width(), format, 0)));
}
// static
@@ -70,6 +73,7 @@ GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.id = id;
handle.offset = 0;
+ handle.stride = gfx::RowSizeForBufferFormat(size.width(), format, 0);
shared_memory.GiveToProcess(child_process, &handle.handle);
return handle;
}
@@ -88,7 +92,7 @@ GpuMemoryBufferImplSharedMemory::CreateFromHandle(
return make_scoped_ptr(new GpuMemoryBufferImplSharedMemory(
handle.id, size, format, callback,
make_scoped_ptr(new base::SharedMemory(handle.handle, false)),
- handle.offset));
+ handle.offset, handle.stride));
}
// static
@@ -162,6 +166,7 @@ base::Closure GpuMemoryBufferImplSharedMemory::AllocateForTesting(
DCHECK(rv);
handle->type = gfx::SHARED_MEMORY_BUFFER;
handle->offset = 0;
+ handle->stride = gfx::RowSizeForBufferFormat(size.width(), format, 0);
handle->handle = base::SharedMemory::DuplicateHandle(shared_memory.handle());
return base::Bind(&Noop);
}
@@ -172,6 +177,8 @@ bool GpuMemoryBufferImplSharedMemory::Map() {
// Map the buffer first time Map() is called then keep it mapped for the
// lifetime of the buffer. This avoids mapping the buffer unless necessary.
if (!shared_memory_->memory()) {
+ DCHECK_EQ(static_cast<size_t>(stride_),
+ gfx::RowSizeForBufferFormat(size_.width(), format_, 0));
size_t buffer_size = gfx::BufferSizeForBufferFormat(size_, format_);
// Note: offset_ != 0 is not common use-case. To keep it simple we
// map offset + buffer_size here but this can be avoided using MapAt().
@@ -205,6 +212,7 @@ gfx::GpuMemoryBufferHandle GpuMemoryBufferImplSharedMemory::GetHandle() const {
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.id = id_;
handle.offset = offset_;
+ handle.stride = stride_;
handle.handle = shared_memory_->handle();
return handle;
}
diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
index bb5f29b..22f292a 100644
--- a/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
+++ b/content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h
@@ -59,10 +59,12 @@ class CONTENT_EXPORT GpuMemoryBufferImplSharedMemory
gfx::BufferFormat format,
const DestructionCallback& callback,
scoped_ptr<base::SharedMemory> shared_memory,
- size_t offset);
+ size_t offset,
+ int stride);
scoped_ptr<base::SharedMemory> shared_memory_;
size_t offset_;
+ int stride_;
DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplSharedMemory);
};
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index 746bc11..f8559b9 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -17,6 +17,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/location.h"
+#include "base/numerics/safe_conversions.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
@@ -1040,10 +1041,14 @@ scoped_refptr<gl::GLImage> GpuChannel::CreateImageForGpuMemoryBuffer(
uint32 internalformat) {
switch (handle.type) {
case gfx::SHARED_MEMORY_BUFFER: {
+ if (!base::IsValueInRangeForNumericType<size_t>(handle.stride))
+ return nullptr;
scoped_refptr<gl::GLImageSharedMemory> image(
new gl::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle.handle, handle.id, format, handle.offset))
+ if (!image->Initialize(handle.handle, handle.id, format, handle.offset,
+ handle.stride)) {
return nullptr;
+ }
return image;
}
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 5e1921a..3f22542 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -15,6 +15,7 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
+#include "base/numerics/safe_conversions.h"
#include "base/sequence_checker.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
@@ -114,6 +115,7 @@ gfx::GpuMemoryBufferHandle ShareGpuMemoryBufferToGpuThread(
handle.type = gfx::SHARED_MEMORY_BUFFER;
handle.handle = ShareToGpuThread(source_handle.handle);
handle.offset = source_handle.offset;
+ handle.stride = source_handle.stride;
*requires_sync_point = false;
return handle;
}
@@ -735,9 +737,14 @@ void InProcessCommandBuffer::CreateImageOnGpuThread(
switch (handle.type) {
case gfx::SHARED_MEMORY_BUFFER: {
+ if (!base::IsValueInRangeForNumericType<size_t>(handle.stride)) {
+ LOG(ERROR) << "Invalid stride for image.";
+ return;
+ }
scoped_refptr<gl::GLImageSharedMemory> image(
new gl::GLImageSharedMemory(size, internalformat));
- if (!image->Initialize(handle.handle, handle.id, format, handle.offset)) {
+ if (!image->Initialize(handle.handle, handle.id, format, handle.offset,
+ handle.stride)) {
LOG(ERROR) << "Failed to initialize image.";
return;
}
diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h
index 217aae2..47d277e 100644
--- a/ui/gfx/gpu_memory_buffer.h
+++ b/ui/gfx/gpu_memory_buffer.h
@@ -39,6 +39,7 @@ struct GFX_EXPORT GpuMemoryBufferHandle {
GpuMemoryBufferId id;
base::SharedMemoryHandle handle;
uint32_t offset;
+ int32_t stride;
#if defined(USE_OZONE)
NativePixmapHandle native_pixmap_handle;
#endif
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc
index 03391ba..3bdf596 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;
diff --git a/ui/gl/gl_image_memory.h b/ui/gl/gl_image_memory.h
index 3ce0440..5492ec3 100644
--- a/ui/gl/gl_image_memory.h
+++ b/ui/gl/gl_image_memory.h
@@ -16,7 +16,9 @@ class GL_EXPORT GLImageMemory : public GLImage {
public:
GLImageMemory(const gfx::Size& size, unsigned internalformat);
- bool Initialize(const unsigned char* memory, gfx::BufferFormat format);
+ bool Initialize(const unsigned char* memory,
+ gfx::BufferFormat format,
+ size_t stride);
// Overridden from GLImage:
void Destroy(bool have_context) override;
@@ -40,12 +42,14 @@ class GL_EXPORT GLImageMemory : public GLImage {
~GLImageMemory() override;
gfx::BufferFormat format() const { return format_; }
+ size_t stride() const { return stride_; }
private:
const gfx::Size size_;
const unsigned internalformat_;
const unsigned char* memory_;
gfx::BufferFormat format_;
+ size_t stride_;
DISALLOW_COPY_AND_ASSIGN(GLImageMemory);
};
diff --git a/ui/gl/gl_image_ref_counted_memory.cc b/ui/gl/gl_image_ref_counted_memory.cc
index a417f15..1831c08 100644
--- a/ui/gl/gl_image_ref_counted_memory.cc
+++ b/ui/gl/gl_image_ref_counted_memory.cc
@@ -9,6 +9,7 @@
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/process_memory_dump.h"
+#include "ui/gfx/buffer_format_util.h"
namespace gl {
@@ -23,8 +24,11 @@ GLImageRefCountedMemory::~GLImageRefCountedMemory() {
bool GLImageRefCountedMemory::Initialize(
base::RefCountedMemory* ref_counted_memory,
gfx::BufferFormat format) {
- if (!GLImageMemory::Initialize(ref_counted_memory->front(), format))
+ if (!GLImageMemory::Initialize(
+ ref_counted_memory->front(), format,
+ gfx::RowSizeForBufferFormat(GetSize().width(), format, 0))) {
return false;
+ }
DCHECK(!ref_counted_memory_.get());
ref_counted_memory_ = ref_counted_memory;
diff --git a/ui/gl/gl_image_shared_memory.cc b/ui/gl/gl_image_shared_memory.cc
index 6ea5553..21c72c1 100644
--- a/ui/gl/gl_image_shared_memory.cc
+++ b/ui/gl/gl_image_shared_memory.cc
@@ -28,9 +28,14 @@ bool GLImageSharedMemory::Initialize(
const base::SharedMemoryHandle& handle,
gfx::GenericSharedMemoryId shared_memory_id,
gfx::BufferFormat format,
- size_t offset) {
- size_t size_in_bytes;
- if (!BufferSizeForBufferFormatChecked(GetSize(), format, &size_in_bytes))
+ size_t offset,
+ size_t stride) {
+ if (NumberOfPlanesForBufferFormat(format) != 1)
+ return false;
+
+ base::CheckedNumeric<size_t> checked_size = stride;
+ checked_size *= GetSize().height();
+ if (!checked_size.IsValid())
return false;
if (!base::SharedMemory::IsHandleValid(handle))
@@ -52,22 +57,21 @@ bool GLImageSharedMemory::Initialize(
size_t map_offset = base::SysInfo::VMAllocationGranularity() *
(offset / base::SysInfo::VMAllocationGranularity());
- base::CheckedNumeric<size_t> checked_size_to_map_in_bytes = size_in_bytes;
- checked_size_to_map_in_bytes += memory_offset;
- if (!checked_size_to_map_in_bytes.IsValid())
+ checked_size += memory_offset;
+ if (!checked_size.IsValid())
return false;
scoped_ptr<base::SharedMemory> duped_shared_memory(
new base::SharedMemory(duped_shared_memory_handle, true));
if (!duped_shared_memory->MapAt(static_cast<off_t>(map_offset),
- checked_size_to_map_in_bytes.ValueOrDie())) {
+ checked_size.ValueOrDie())) {
DVLOG(0) << "Failed to map shared memory.";
return false;
}
if (!GLImageMemory::Initialize(
static_cast<uint8_t*>(duped_shared_memory->memory()) + memory_offset,
- format)) {
+ format, stride)) {
return false;
}
@@ -89,7 +93,7 @@ void GLImageSharedMemory::OnMemoryDump(
size_t size_in_bytes = 0;
if (shared_memory_)
- size_in_bytes = BufferSizeForBufferFormat(GetSize(), format());
+ size_in_bytes = stride() * GetSize().height();
// Dump under "/shared_memory", as the base class may also dump to
// "/texture_memory".
diff --git a/ui/gl/gl_image_shared_memory.h b/ui/gl/gl_image_shared_memory.h
index e3425d2..3c1564e 100644
--- a/ui/gl/gl_image_shared_memory.h
+++ b/ui/gl/gl_image_shared_memory.h
@@ -23,7 +23,8 @@ class GL_EXPORT GLImageSharedMemory : public GLImageMemory {
bool Initialize(const base::SharedMemoryHandle& handle,
gfx::GenericSharedMemoryId shared_memory_id,
gfx::BufferFormat format,
- size_t offset);
+ size_t offset,
+ size_t stride);
// Overridden from GLImage:
void Destroy(bool have_context) override;
diff --git a/ui/gl/gl_image_shared_memory_unittest.cc b/ui/gl/gl_image_shared_memory_unittest.cc
index 2769960..da6feac 100644
--- a/ui/gl/gl_image_shared_memory_unittest.cc
+++ b/ui/gl/gl_image_shared_memory_unittest.cc
@@ -30,7 +30,8 @@ class GLImageSharedMemoryTestDelegate {
size, gl::GLImageMemory::GetInternalFormatForTesting(format)));
rv = image->Initialize(
base::SharedMemory::DuplicateHandle(shared_memory.handle()),
- gfx::GenericSharedMemoryId(0), format, 0);
+ gfx::GenericSharedMemoryId(0), format, 0,
+ gfx::RowSizeForBufferFormat(size.width(), format, 0));
EXPECT_TRUE(rv);
return image;
}
@@ -55,10 +56,13 @@ class GLImageSharedMemoryPoolTestDelegate {
scoped_refptr<gl::GLImage> CreateSolidColorImage(
const gfx::Size& size,
const uint8_t color[4]) const {
- // Create a shared memory segment that is 2 pages larger than image.
+ // Create a shared memory segment that holds an image with a stride that is
+ // twice the row size and 2 pages larger than image.
+ size_t stride = gfx::RowSizeForBufferFormat(
+ size.width(), gfx::BufferFormat::RGBA_8888, 0) *
+ 2;
size_t pool_size =
- gfx::BufferSizeForBufferFormat(size, gfx::BufferFormat::RGBA_8888) +
- base::SysInfo::VMAllocationGranularity() * 3;
+ stride * size.height() + base::SysInfo::VMAllocationGranularity() * 3;
base::SharedMemory shared_memory;
bool rv = shared_memory.CreateAndMapAnonymous(pool_size);
DCHECK(rv);
@@ -67,9 +71,7 @@ class GLImageSharedMemoryPoolTestDelegate {
// Place buffer at a non-zero non-page-aligned offset in shared memory.
size_t buffer_offset = 3 * base::SysInfo::VMAllocationGranularity() / 2;
GLImageTestSupport::SetBufferDataToColor(
- size.width(), size.height(),
- static_cast<int>(RowSizeForBufferFormat(
- size.width(), gfx::BufferFormat::RGBA_8888, 0)),
+ size.width(), size.height(), static_cast<int>(stride),
gfx::BufferFormat::RGBA_8888, color,
reinterpret_cast<uint8_t*>(shared_memory.memory()) + buffer_offset);
scoped_refptr<gl::GLImageSharedMemory> image(
@@ -77,7 +79,7 @@ class GLImageSharedMemoryPoolTestDelegate {
rv = image->Initialize(
base::SharedMemory::DuplicateHandle(shared_memory.handle()),
gfx::GenericSharedMemoryId(0), gfx::BufferFormat::RGBA_8888,
- buffer_offset);
+ buffer_offset, stride);
EXPECT_TRUE(rv);
return image;
}