diff options
author | reveman <reveman@chromium.org> | 2015-11-10 10:12:52 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-10 18:13:31 +0000 |
commit | f2322f7fb01ba0dc954c94f48bb5e9a9a41c32e2 (patch) | |
tree | 660bc2b43446109c3235cd83aa90b21c095fb823 | |
parent | 76c1cfc82d78fc8eb503ba300021a816d39538d5 (diff) | |
download | chromium_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}
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; } |