diff options
author | emircan <emircan@chromium.org> | 2015-04-07 23:25:00 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-08 06:25:48 +0000 |
commit | 607ed17ba5d0d1c67901ecc7160db660f08bd831 (patch) | |
tree | 8c8d692aaff4c1110998718c9cd587e0e76a47ee | |
parent | 7e576157bba19b8918f0ad2e3a43d0171a675155 (diff) | |
download | chromium_src-607ed17ba5d0d1c67901ecc7160db660f08bd831.zip chromium_src-607ed17ba5d0d1c67901ecc7160db660f08bd831.tar.gz chromium_src-607ed17ba5d0d1c67901ecc7160db660f08bd831.tar.bz2 |
We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[0] https://codereview.chromium.org/1024113003/#ps200001
In this CL:
- I added a new format gfx::GpuMemoryBuffer::YUV_420
- Implemented helper functions to use with it on GpuMemoryBufferImpl.
- I added support in GpuMemoryBufferImplSharedMemory and GpuMemoryBufferFactorySharedMemory
- I added { gfx::GpuMemoryBuffer::YUV_420, gfx::GpuMemoryBuffer::MAP } as a supported config for testing
- I added support for multi plane in test implementations: test_gpu_memory_buffer_manager, gl_manager, gpu_memory_buffer_impl_unittest
The future steps are:
- Add a new GL_* internalformat corresponding to YUV_420
- Implement support for YUV_420 in GpuMemoryBufferFactoryOzoneNativeBuffer, GLImageLinuxDMABuffer and SurfaceFactoryOzone
- Expose file descriptors for gfx::GpuMemoryBuffer::YUV_420 via Map() or GpuMemoryBufferHandle struct
Check usage of gbm_bo_get_fd() at the lowest gbmbuffer level
- Add support in GLImageSharedMemory and GLImageMemory through Bind functions
- Look for possible use cases of multiple buffers on Android, Mac, and Win platforms
BUG=439520
TEST=content_unittests --gtest_filter=GpuMemoryBufferImplTests.*
content_unittests --gtest_filter=GpuMemoryBufferFactoryTest.*
gl_tests --gtest_filter=GpuMemoryBufferTest*
Review URL: https://codereview.chromium.org/1062853002
Cr-Commit-Position: refs/heads/master@{#324190}
17 files changed, 330 insertions, 114 deletions
diff --git a/cc/test/test_gpu_memory_buffer_manager.cc b/cc/test/test_gpu_memory_buffer_manager.cc index b43cd76..8887feb 100644 --- a/cc/test/test_gpu_memory_buffer_manager.cc +++ b/cc/test/test_gpu_memory_buffer_manager.cc @@ -10,26 +10,82 @@ namespace cc { namespace { -size_t StrideInBytes(size_t width, gfx::GpuMemoryBuffer::Format format) { +size_t NumberOfPlanesForGpuMemoryBufferFormat( + gfx::GpuMemoryBuffer::Format format) { switch (format) { + case gfx::GpuMemoryBuffer::Format::ATC: + case gfx::GpuMemoryBuffer::Format::ATCIA: + case gfx::GpuMemoryBuffer::Format::DXT1: + case gfx::GpuMemoryBuffer::Format::DXT5: + case gfx::GpuMemoryBuffer::Format::ETC1: + case gfx::GpuMemoryBuffer::Format::RGBA_8888: + case gfx::GpuMemoryBuffer::Format::RGBX_8888: + case gfx::GpuMemoryBuffer::Format::BGRA_8888: + return 1; + case gfx::GpuMemoryBuffer::Format::YUV_420: + return 3; + } + NOTREACHED(); + return 0; +} + +size_t SubsamplingFactor(gfx::GpuMemoryBuffer::Format format, int plane) { + switch (format) { + case gfx::GpuMemoryBuffer::ATC: case gfx::GpuMemoryBuffer::ATCIA: + case gfx::GpuMemoryBuffer::DXT1: case gfx::GpuMemoryBuffer::DXT5: + case gfx::GpuMemoryBuffer::ETC1: + case gfx::GpuMemoryBuffer::RGBA_8888: + case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::BGRA_8888: + return 1; + case gfx::GpuMemoryBuffer::YUV_420: { + static size_t factor[] = {1, 2, 2}; + DCHECK_LT(static_cast<size_t>(plane), arraysize(factor)); + return factor[plane]; + } + } + NOTREACHED(); + return 0; +} + +size_t StrideInBytes(size_t width, + gfx::GpuMemoryBuffer::Format format, + int plane) { + switch (format) { + case gfx::GpuMemoryBuffer::ATCIA: + case gfx::GpuMemoryBuffer::DXT5: + DCHECK_EQ(plane, 0); return width; case gfx::GpuMemoryBuffer::ATC: case gfx::GpuMemoryBuffer::DXT1: case gfx::GpuMemoryBuffer::ETC1: + DCHECK_EQ(plane, 0); DCHECK_EQ(width % 2, 0U); return width / 2; case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::RGBX_8888: case gfx::GpuMemoryBuffer::BGRA_8888: + DCHECK_EQ(plane, 0); return width * 4; + case gfx::GpuMemoryBuffer::YUV_420: + return width / SubsamplingFactor(format, plane); } - NOTREACHED(); return 0; } +size_t BufferSizeInBytes(const gfx::Size& size, + gfx::GpuMemoryBuffer::Format format) { + size_t size_in_bytes = 0u; + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format); ++i) { + size_in_bytes += StrideInBytes(size.width(), format, i) * + (size.height() / SubsamplingFactor(format, i)); + } + return size_in_bytes; +} + class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { public: GpuMemoryBufferImpl(const gfx::Size& size, @@ -43,11 +99,17 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { // Overridden from gfx::GpuMemoryBuffer: bool Map(void** data) override { DCHECK(!mapped_); - if (!shared_memory_->Map(StrideInBytes(size_.width(), format_) * - size_.height())) + if (!shared_memory_->Map(BufferSizeInBytes(size_, format_))) return false; mapped_ = true; - *data = shared_memory_->memory(); + data[0] = shared_memory_->memory(); + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format_) - 1; + ++i) { + size_t offset = StrideInBytes(size_.width(), format_, i) * + (size_.height() / SubsamplingFactor(format_, i)); + data[i + 1] = reinterpret_cast<uint8*>(data[i]) + offset; + } + return true; } void Unmap() override { @@ -58,7 +120,10 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { bool IsMapped() const override { return mapped_; } Format GetFormat() const override { return format_; } void GetStride(uint32* stride) const override { - *stride = StrideInBytes(size_.width(), format_); + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format_); + ++i) { + stride[i] = StrideInBytes(size_.width(), format_, i); + } } gfx::GpuMemoryBufferHandle GetHandle() const override { gfx::GpuMemoryBufferHandle handle; @@ -91,8 +156,7 @@ TestGpuMemoryBufferManager::AllocateGpuMemoryBuffer( gfx::GpuMemoryBuffer::Format format, gfx::GpuMemoryBuffer::Usage usage) { scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); - if (!shared_memory->CreateAnonymous(StrideInBytes(size.width(), format) * - size.height())) + if (!shared_memory->CreateAnonymous(BufferSizeInBytes(size, format))) return nullptr; return make_scoped_ptr<gfx::GpuMemoryBuffer>( new GpuMemoryBufferImpl(size, format, shared_memory.Pass())); diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.cc b/content/common/gpu/client/gpu_memory_buffer_impl.cc index 208261d..b8284ec 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl.cc +++ b/content/common/gpu/client/gpu_memory_buffer_impl.cc @@ -77,57 +77,86 @@ GpuMemoryBufferImpl* GpuMemoryBufferImpl::FromClientBuffer( } // static +size_t GpuMemoryBufferImpl::NumberOfPlanesForGpuMemoryBufferFormat( + Format format) { + switch (format) { + case ATC: + case ATCIA: + case DXT1: + case DXT5: + case ETC1: + case RGBA_8888: + case RGBX_8888: + case BGRA_8888: + return 1; + case YUV_420: + return 3; + } + NOTREACHED(); + return 0; +} + +// static bool GpuMemoryBufferImpl::StrideInBytes(size_t width, Format format, + int plane, size_t* stride_in_bytes) { - base::CheckedNumeric<size_t> s = width; switch (format) { case ATCIA: case DXT5: + DCHECK_EQ(plane, 0); *stride_in_bytes = width; return true; case ATC: case DXT1: case ETC1: + DCHECK_EQ(plane, 0); DCHECK_EQ(width % 2, 0U); - s /= 2; - if (!s.IsValid()) - return false; - - *stride_in_bytes = s.ValueOrDie(); + *stride_in_bytes = width / 2; return true; case RGBA_8888: case RGBX_8888: - case BGRA_8888: + case BGRA_8888: { + base::CheckedNumeric<size_t> s = width; + DCHECK_EQ(plane, 0); s *= 4; if (!s.IsValid()) return false; - *stride_in_bytes = s.ValueOrDie(); return true; + } + case YUV_420: { + DCHECK_EQ(width % 2, 0u); + *stride_in_bytes = width / SubsamplingFactor(format, plane); + return true; + } } - NOTREACHED(); return false; } // static -size_t GpuMemoryBufferImpl::NumberOfPlanesForGpuMemoryBufferFormat( - gfx::GpuMemoryBuffer::Format format) { +size_t GpuMemoryBufferImpl::SubsamplingFactor( + Format format, + int plane) { switch (format) { - case gfx::GpuMemoryBuffer::Format::ATC: - case gfx::GpuMemoryBuffer::Format::ATCIA: - case gfx::GpuMemoryBuffer::Format::DXT1: - case gfx::GpuMemoryBuffer::Format::DXT5: - case gfx::GpuMemoryBuffer::Format::ETC1: - case gfx::GpuMemoryBuffer::Format::RGBA_8888: - case gfx::GpuMemoryBuffer::Format::RGBX_8888: - case gfx::GpuMemoryBuffer::Format::BGRA_8888: + case ATC: + case ATCIA: + case DXT1: + case DXT5: + case ETC1: + case RGBA_8888: + case RGBX_8888: + case BGRA_8888: return 1; - default: - NOTREACHED(); - return 0; + case YUV_420: { + static size_t factor[] = {1, 2, 2}; + DCHECK_LT(static_cast<size_t>(plane), arraysize(factor)); + return factor[plane]; + } } + NOTREACHED(); + return 0; } gfx::GpuMemoryBuffer::Format GpuMemoryBufferImpl::GetFormat() const { diff --git a/content/common/gpu/client/gpu_memory_buffer_impl.h b/content/common/gpu/client/gpu_memory_buffer_impl.h index cd8c108..31b28bc 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl.h +++ b/content/common/gpu/client/gpu_memory_buffer_impl.h @@ -33,15 +33,19 @@ class CONTENT_EXPORT GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { // Type-checking upcast routine. Returns an NULL on failure. static GpuMemoryBufferImpl* FromClientBuffer(ClientBuffer buffer); + // Returns the number of planes based on the format of the buffer. + static size_t NumberOfPlanesForGpuMemoryBufferFormat(Format format); + // Calculates the number of bytes that an implementation must use to store // one row of pixel data. static bool StrideInBytes(size_t width, Format format, + int plane, size_t* stride_in_bytes); - // Returns the number of planes based on the format of the buffer. - static size_t NumberOfPlanesForGpuMemoryBufferFormat( - gfx::GpuMemoryBuffer::Format format); + // Returns the subsampling factor applied to the given zero-indexed |plane| of + // the |format| both horizontally and vertically. + static size_t SubsamplingFactor(Format format, int plane); // Overridden from gfx::GpuMemoryBuffer: bool IsMapped() const override; 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 3d3aee9..9155205 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 @@ -36,18 +36,12 @@ scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImplSharedMemory::Create( gfx::GpuMemoryBufferId id, const gfx::Size& size, Format format) { - scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); - - size_t stride_in_bytes = 0; - if (!StrideInBytes(size.width(), format, &stride_in_bytes)) + size_t buffer_size = 0u; + if (!BufferSizeInBytes(size, format, &buffer_size)) return scoped_ptr<GpuMemoryBufferImpl>(); - base::CheckedNumeric<size_t> size_in_bytes = stride_in_bytes; - size_in_bytes *= size.height(); - if (!size_in_bytes.IsValid()) - return scoped_ptr<GpuMemoryBufferImpl>(); - - if (!shared_memory->CreateAndMapAnonymous(size_in_bytes.ValueOrDie())) + scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); + if (!shared_memory->CreateAndMapAnonymous(buffer_size)) return scoped_ptr<GpuMemoryBufferImpl>(); return make_scoped_ptr(new GpuMemoryBufferImplSharedMemory( @@ -61,17 +55,12 @@ GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( const gfx::Size& size, Format format, base::ProcessHandle child_process) { - size_t stride_in_bytes = 0; - if (!StrideInBytes(size.width(), format, &stride_in_bytes)) - return gfx::GpuMemoryBufferHandle(); - - base::CheckedNumeric<int> buffer_size = stride_in_bytes; - buffer_size *= size.height(); - if (!buffer_size.IsValid()) + size_t buffer_size = 0u; + if (!BufferSizeInBytes(size, format, &buffer_size)) return gfx::GpuMemoryBufferHandle(); base::SharedMemory shared_memory; - if (!shared_memory.CreateAnonymous(buffer_size.ValueOrDie())) + if (!shared_memory.CreateAnonymous(buffer_size)) return gfx::GpuMemoryBufferHandle(); gfx::GpuMemoryBufferHandle handle; @@ -82,6 +71,27 @@ GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( } // static +bool GpuMemoryBufferImplSharedMemory::BufferSizeInBytes(const gfx::Size& size, + Format format, + size_t* size_in_bytes) { + base::CheckedNumeric<size_t> checked_size_in_bytes = 0u; + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format); ++i) { + size_t stride_in_bytes = 0; + if (!StrideInBytes(size.width(), format, i, &stride_in_bytes)) + return false; + base::CheckedNumeric<size_t> checked_plane_size_in_bytes = stride_in_bytes; + checked_plane_size_in_bytes *= size.height() / SubsamplingFactor(format, i); + if (!checked_plane_size_in_bytes.IsValid()) + return false; + checked_size_in_bytes += checked_plane_size_in_bytes.ValueOrDie(); + if (!checked_size_in_bytes.IsValid()) + return false; + } + *size_in_bytes = checked_size_in_bytes.ValueOrDie(); + return true; +} + +// static scoped_ptr<GpuMemoryBufferImpl> GpuMemoryBufferImplSharedMemory::CreateFromHandle( const gfx::GpuMemoryBufferHandle& handle, @@ -91,18 +101,13 @@ GpuMemoryBufferImplSharedMemory::CreateFromHandle( if (!base::SharedMemory::IsHandleValid(handle.handle)) return scoped_ptr<GpuMemoryBufferImpl>(); - size_t stride_in_bytes = 0; - if (!StrideInBytes(size.width(), format, &stride_in_bytes)) - return scoped_ptr<GpuMemoryBufferImpl>(); - - base::CheckedNumeric<size_t> size_in_bytes = stride_in_bytes; - size_in_bytes *= size.height(); - if (!size_in_bytes.IsValid()) + size_t buffer_size = 0u; + if (!BufferSizeInBytes(size, format, &buffer_size)) return scoped_ptr<GpuMemoryBufferImpl>(); scoped_ptr<base::SharedMemory> shared_memory( new base::SharedMemory(handle.handle, false)); - if (!shared_memory->Map(size_in_bytes.ValueOrDie())) + if (!shared_memory->Map(buffer_size)) return scoped_ptr<GpuMemoryBufferImpl>(); return make_scoped_ptr<GpuMemoryBufferImpl>( @@ -124,6 +129,7 @@ bool GpuMemoryBufferImplSharedMemory::IsFormatSupported(Format format) { case ETC1: case RGBA_8888: case BGRA_8888: + case YUV_420: return true; case RGBX_8888: return false; @@ -150,6 +156,15 @@ bool GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat( case BGRA_8888: case RGBX_8888: return true; + case YUV_420: { + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format); + ++i) { + size_t factor = SubsamplingFactor(format, i); + if (size.width() % factor || size.height() % factor) + return false; + } + return true; + } } NOTREACHED(); @@ -158,8 +173,19 @@ bool GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat( bool GpuMemoryBufferImplSharedMemory::Map(void** data) { DCHECK(!mapped_); + data[0] = shared_memory_->memory(); + // Map the other planes if they exist. + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format_) - 1; + ++i) { + size_t stride_in_bytes = 0; + bool valid_stride = + StrideInBytes(size_.width(), format_, i, &stride_in_bytes); + DCHECK(valid_stride); + data[i + 1] = + reinterpret_cast<uint8*>(data[i]) + + stride_in_bytes * (size_.height() / SubsamplingFactor(format_, i)); + } mapped_ = true; - *data = shared_memory_->memory(); return true; } @@ -169,10 +195,13 @@ void GpuMemoryBufferImplSharedMemory::Unmap() { } void GpuMemoryBufferImplSharedMemory::GetStride(uint32* stride) const { - size_t stride_in_bytes = 0; - bool valid_stride = StrideInBytes(size_.width(), format_, &stride_in_bytes); - DCHECK(valid_stride); - *stride = stride_in_bytes; + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format_); ++i) { + size_t stride_in_bytes = 0; + bool valid_stride = + StrideInBytes(size_.width(), format_, i, &stride_in_bytes); + DCHECK(valid_stride); + stride[i] = stride_in_bytes; + } } gfx::GpuMemoryBufferHandle GpuMemoryBufferImplSharedMemory::GetHandle() const { 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 c7eb80c..e93ab32 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 @@ -24,6 +24,12 @@ class GpuMemoryBufferImplSharedMemory : public GpuMemoryBufferImpl { Format format, base::ProcessHandle child_process); + // Calculates the number of bytes used to store all the planes of a given + // |format|. + static bool BufferSizeInBytes(const gfx::Size& size, + Format format, + size_t* size_in_bytes); + static scoped_ptr<GpuMemoryBufferImpl> CreateFromHandle( const gfx::GpuMemoryBufferHandle& handle, const gfx::Size& size, diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc b/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc index a1d0e5c..8ed95a9 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc +++ b/content/common/gpu/client/gpu_memory_buffer_impl_surface_texture.cc @@ -23,6 +23,7 @@ int WindowFormat(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBX_8888: case gfx::GpuMemoryBuffer::BGRA_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } @@ -81,7 +82,7 @@ bool GpuMemoryBufferImplSurfaceTexture::Map(void** data) { } size_t stride_in_bytes = 0; - if (!StrideInBytes(buffer.stride, format_, &stride_in_bytes)) + if (!StrideInBytes(buffer.stride, format_, 0, &stride_in_bytes)) return false; DCHECK_LE(size_.width(), buffer.stride); diff --git a/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc b/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc index ba55d78..d73dae7 100644 --- a/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc +++ b/content/common/gpu/client/gpu_memory_buffer_impl_unittest.cc @@ -52,7 +52,7 @@ class GpuMemoryBufferImplTest TEST_P(GpuMemoryBufferImplTest, CreateFromHandle) { const int kBufferId = 1; - gfx::Size buffer_size(1, 1); + gfx::Size buffer_size(8, 8); for (auto configuration : supported_configurations_) { scoped_ptr<GpuMemoryBufferImpl> buffer( @@ -79,42 +79,50 @@ TEST_P(GpuMemoryBufferImplTest, CreateFromHandle) { TEST_P(GpuMemoryBufferImplTest, Map) { const int kBufferId = 1; - gfx::Size buffer_size(1, 1); + gfx::Size buffer_size(2, 2); for (auto configuration : supported_configurations_) { if (configuration.usage != gfx::GpuMemoryBuffer::MAP) continue; - size_t width_in_bytes = 0; - EXPECT_TRUE(GpuMemoryBufferImpl::StrideInBytes( - buffer_size.width(), configuration.format, &width_in_bytes)); - EXPECT_GT(width_in_bytes, 0u); - scoped_ptr<char[]> data(new char[width_in_bytes]); - memset(data.get(), 0x2a, width_in_bytes); - scoped_ptr<GpuMemoryBufferImpl> buffer( GpuMemoryBufferImpl::CreateFromHandle( - CreateGpuMemoryBuffer(kBufferId, - buffer_size, - configuration.format, + CreateGpuMemoryBuffer(kBufferId, buffer_size, configuration.format, configuration.usage), - buffer_size, - configuration.format, + buffer_size, configuration.format, base::Bind(&GpuMemoryBufferImplTest::DestroyGpuMemoryBuffer, - base::Unretained(this), - kBufferId))); + base::Unretained(this), kBufferId))); ASSERT_TRUE(buffer); EXPECT_FALSE(buffer->IsMapped()); - void* memory; - bool rv = buffer->Map(&memory); + size_t num_planes = + GpuMemoryBufferImpl::NumberOfPlanesForGpuMemoryBufferFormat( + configuration.format); + + // Map buffer into user space. + scoped_ptr<void*[]> mapped_buffers(new void*[num_planes]); + bool rv = buffer->Map(mapped_buffers.get()); ASSERT_TRUE(rv); EXPECT_TRUE(buffer->IsMapped()); - uint32 stride; - buffer->GetStride(&stride); - EXPECT_GE(stride, width_in_bytes); - memcpy(memory, data.get(), width_in_bytes); - EXPECT_EQ(memcmp(memory, data.get(), width_in_bytes), 0); + + // Get strides. + scoped_ptr<uint32[]> strides(new uint32[num_planes]); + buffer->GetStride(strides.get()); + + // Copy and compare mapped buffers. + for (size_t i = 0; i < num_planes; ++i) { + size_t width_in_bytes = 0u; + EXPECT_TRUE(GpuMemoryBufferImpl::StrideInBytes( + buffer_size.width(), configuration.format, i, &width_in_bytes)); + EXPECT_GT(width_in_bytes, 0u); + EXPECT_GE(strides[i], width_in_bytes); + + scoped_ptr<char[]> data(new char[width_in_bytes]); + memset(data.get(), 0x2a + i, width_in_bytes); + memcpy(mapped_buffers[i], data.get(), width_in_bytes); + EXPECT_EQ(memcmp(mapped_buffers[i], data.get(), width_in_bytes), 0); + } + buffer->Unmap(); EXPECT_FALSE(buffer->IsMapped()); } diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc index 604c1b4..2737a4d 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc +++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc @@ -38,6 +38,7 @@ int32 BytesPerPixel(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } @@ -57,6 +58,7 @@ int32 PixelFormat(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } diff --git a/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc b/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc index 790fcab..992decd 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc +++ b/content/common/gpu/gpu_memory_buffer_factory_shared_memory.cc @@ -7,7 +7,7 @@ #include <vector> #include "base/logging.h" -#include "content/common/gpu/client/gpu_memory_buffer_impl.h" +#include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" #include "ui/gl/gl_image.h" #include "ui/gl/gl_image_shared_memory.h" @@ -24,7 +24,8 @@ void GpuMemoryBufferFactorySharedMemory:: std::vector<Configuration>* configurations) { const Configuration supported_configurations[] = { { gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::MAP }, - { gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP } + { gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP }, + { gfx::GpuMemoryBuffer::YUV_420, gfx::GpuMemoryBuffer::MAP } }; configurations->assign( supported_configurations, @@ -39,19 +40,13 @@ GpuMemoryBufferFactorySharedMemory::CreateGpuMemoryBuffer( gfx::GpuMemoryBuffer::Usage usage, int client_id, gfx::PluginWindowHandle surface_handle) { - base::SharedMemory shared_memory; - - size_t stride_in_bytes = 0; - if (!GpuMemoryBufferImpl::StrideInBytes( - size.width(), format, &stride_in_bytes)) + size_t buffer_size = 0u; + if (!GpuMemoryBufferImplSharedMemory::BufferSizeInBytes(size, format, + &buffer_size)) return gfx::GpuMemoryBufferHandle(); - base::CheckedNumeric<size_t> size_in_bytes = stride_in_bytes; - size_in_bytes *= size.height(); - if (!size_in_bytes.IsValid()) - return gfx::GpuMemoryBufferHandle(); - - if (!shared_memory.CreateAnonymous(size_in_bytes.ValueOrDie())) + base::SharedMemory shared_memory; + if (!shared_memory.CreateAnonymous(buffer_size)) return gfx::GpuMemoryBufferHandle(); gfx::GpuMemoryBufferHandle handle; diff --git a/content/common/gpu/gpu_memory_buffer_factory_unittest.cc b/content/common/gpu/gpu_memory_buffer_factory_unittest.cc index a191433..f9dc7e1 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_unittest.cc +++ b/content/common/gpu/gpu_memory_buffer_factory_unittest.cc @@ -31,7 +31,7 @@ TEST_P(GpuMemoryBufferFactoryTest, CreateAndDestroy) { const int kBufferId = 1; const int kClientId = 1; - gfx::Size buffer_size(1, 1); + gfx::Size buffer_size(2, 2); for (auto configuration : supported_configurations_) { gfx::GpuMemoryBufferHandle handle = factory_->CreateGpuMemoryBuffer( diff --git a/gpu/command_buffer/service/image_factory.cc b/gpu/command_buffer/service/image_factory.cc index a80d17c..f09cfb8 100644 --- a/gpu/command_buffer/service/image_factory.cc +++ b/gpu/command_buffer/service/image_factory.cc @@ -80,6 +80,7 @@ bool ImageFactory::IsGpuMemoryBufferFormatSupported( return capabilities.texture_format_etc1; case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: return true; } @@ -103,6 +104,7 @@ bool ImageFactory::IsImageSizeValidForGpuMemoryBufferFormat( case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::BGRA_8888: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: return true; } diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc index 052bd3d..9368da5 100644 --- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc +++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc @@ -98,6 +98,7 @@ std::vector<uint8> GetTexturePixel(const gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return std::vector<uint8>(); } @@ -123,6 +124,7 @@ std::vector<uint8> GetFramebufferPixel( case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return std::vector<uint8>(); } @@ -143,6 +145,7 @@ GLenum InternalFormat(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc index 67bdbb8..3a3d7e9 100644 --- a/gpu/command_buffer/tests/gl_manager.cc +++ b/gpu/command_buffer/tests/gl_manager.cc @@ -38,28 +38,85 @@ namespace gpu { namespace { -size_t StrideInBytes(size_t width, gfx::GpuMemoryBuffer::Format format) { +size_t NumberOfPlanesForGpuMemoryBufferFormat( + gfx::GpuMemoryBuffer::Format format) { + switch (format) { + case gfx::GpuMemoryBuffer::Format::ATC: + case gfx::GpuMemoryBuffer::Format::ATCIA: + case gfx::GpuMemoryBuffer::Format::DXT1: + case gfx::GpuMemoryBuffer::Format::DXT5: + case gfx::GpuMemoryBuffer::Format::ETC1: + case gfx::GpuMemoryBuffer::Format::RGBA_8888: + case gfx::GpuMemoryBuffer::Format::RGBX_8888: + case gfx::GpuMemoryBuffer::Format::BGRA_8888: + return 1; + case gfx::GpuMemoryBuffer::Format::YUV_420: + return 3; + } + NOTREACHED(); + return 0; +} + +size_t SubsamplingFactor(gfx::GpuMemoryBuffer::Format format, int plane) { switch (format) { + case gfx::GpuMemoryBuffer::ATC: case gfx::GpuMemoryBuffer::ATCIA: + case gfx::GpuMemoryBuffer::DXT1: case gfx::GpuMemoryBuffer::DXT5: + case gfx::GpuMemoryBuffer::ETC1: + case gfx::GpuMemoryBuffer::RGBA_8888: + case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::BGRA_8888: + return 1; + case gfx::GpuMemoryBuffer::YUV_420: { + static size_t factor[] = {1, 2, 2}; + DCHECK_LT(static_cast<size_t>(plane), arraysize(factor)); + return factor[plane]; + } + } + NOTREACHED(); + return 0; +} + +size_t StrideInBytes(size_t width, + gfx::GpuMemoryBuffer::Format format, + int plane) { + switch (format) { + case gfx::GpuMemoryBuffer::ATCIA: + case gfx::GpuMemoryBuffer::DXT5: + DCHECK_EQ(plane, 0); return width; case gfx::GpuMemoryBuffer::ATC: case gfx::GpuMemoryBuffer::DXT1: case gfx::GpuMemoryBuffer::ETC1: + DCHECK_EQ(plane, 0); DCHECK_EQ(width % 2, 0U); return width / 2; case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::BGRA_8888: + DCHECK_EQ(plane, 0); return width * 4; case gfx::GpuMemoryBuffer::RGBX_8888: NOTREACHED(); return 0; + case gfx::GpuMemoryBuffer::YUV_420: + return width / SubsamplingFactor(format, plane); } NOTREACHED(); return 0; } +size_t BufferSizeInBytes(const gfx::Size& size, + gfx::GpuMemoryBuffer::Format format) { + size_t size_in_bytes = 0u; + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format); ++i) { + size_in_bytes += StrideInBytes(size.width(), format, i) * + (size.height() / SubsamplingFactor(format, i)); + } + return size_in_bytes; +} + class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { public: GpuMemoryBufferImpl(base::RefCountedBytes* bytes, @@ -73,15 +130,24 @@ class GpuMemoryBufferImpl : public gfx::GpuMemoryBuffer { // Overridden from gfx::GpuMemoryBuffer: bool Map(void** data) override { + data[0] = &bytes_->data().front(); + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format_) - 1; + ++i) { + size_t offset = StrideInBytes(size_.width(), format_, i) * + (size_.height() / SubsamplingFactor(format_, i)); + data[i + 1] = reinterpret_cast<uint8*>(data[i]) + offset; + } mapped_ = true; - *data = &bytes_->data().front(); return true; } void Unmap() override { mapped_ = false; } bool IsMapped() const override { return mapped_; } Format GetFormat() const override { return format_; } void GetStride(uint32* stride) const override { - *stride = StrideInBytes(size_.width(), format_); + for (size_t i = 0; i < NumberOfPlanesForGpuMemoryBufferFormat(format_); + ++i) { + stride[i] = StrideInBytes(size_.width(), format_, i); + } } gfx::GpuMemoryBufferHandle GetHandle() const override { NOTREACHED(); @@ -143,8 +209,7 @@ GLManager::~GLManager() { scoped_ptr<gfx::GpuMemoryBuffer> GLManager::CreateGpuMemoryBuffer( const gfx::Size& size, gfx::GpuMemoryBuffer::Format format) { - std::vector<unsigned char> data( - StrideInBytes(size.width(), format) * size.height(), 0); + std::vector<unsigned char> data(BufferSizeInBytes(size, format), 0); scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes(data)); return make_scoped_ptr<gfx::GpuMemoryBuffer>( new GpuMemoryBufferImpl(bytes.get(), size, format)); diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h index e56009f..6383a13 100644 --- a/ui/gfx/gpu_memory_buffer.h +++ b/ui/gfx/gpu_memory_buffer.h @@ -51,8 +51,9 @@ class GFX_EXPORT GpuMemoryBuffer { RGBA_8888, RGBX_8888, BGRA_8888, + YUV_420, - FORMAT_LAST = BGRA_8888 + FORMAT_LAST = YUV_420 }; // The usage mode affects how a buffer can be used. Only buffers created with diff --git a/ui/gl/gl_image_linux_dma_buffer.cc b/ui/gl/gl_image_linux_dma_buffer.cc index 04ad06b..080c9b5 100644 --- a/ui/gl/gl_image_linux_dma_buffer.cc +++ b/ui/gl/gl_image_linux_dma_buffer.cc @@ -39,6 +39,7 @@ bool ValidFormat(unsigned internalformat, gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::BGRA_8888: + case gfx::GpuMemoryBuffer::YUV_420: return false; } NOTREACHED(); @@ -54,6 +55,7 @@ bool ValidFormat(unsigned internalformat, gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBX_8888: case gfx::GpuMemoryBuffer::RGBA_8888: + case gfx::GpuMemoryBuffer::YUV_420: return false; } NOTREACHED(); @@ -75,6 +77,7 @@ EGLint FourCC(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBA_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc index 9022917..ff9c97e 100644 --- a/ui/gl/gl_image_memory.cc +++ b/ui/gl/gl_image_memory.cc @@ -38,6 +38,7 @@ bool ValidFormat(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::BGRA_8888: return true; case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: return false; } @@ -52,6 +53,7 @@ bool IsCompressedFormat(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::DXT1: case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: + case gfx::GpuMemoryBuffer::YUV_420: return true; case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::BGRA_8888: @@ -80,6 +82,7 @@ GLenum TextureFormat(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::BGRA_8888: return GL_BGRA_EXT; case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } @@ -103,6 +106,7 @@ GLenum DataType(gfx::GpuMemoryBuffer::Format format) { case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return 0; } @@ -153,10 +157,6 @@ bool GLImageMemory::StrideInBytes(size_t width, size_t* stride_in_bytes) { base::CheckedNumeric<size_t> s = width; switch (format) { - case gfx::GpuMemoryBuffer::ATCIA: - case gfx::GpuMemoryBuffer::DXT5: - *stride_in_bytes = width; - return true; case gfx::GpuMemoryBuffer::ATC: case gfx::GpuMemoryBuffer::DXT1: case gfx::GpuMemoryBuffer::ETC1: @@ -164,18 +164,21 @@ bool GLImageMemory::StrideInBytes(size_t width, s /= 2; if (!s.IsValid()) return false; - *stride_in_bytes = s.ValueOrDie(); return true; + case gfx::GpuMemoryBuffer::ATCIA: + case gfx::GpuMemoryBuffer::DXT5: + *stride_in_bytes = width; + return true; case gfx::GpuMemoryBuffer::RGBA_8888: case gfx::GpuMemoryBuffer::BGRA_8888: s *= 4; if (!s.IsValid()) return false; - *stride_in_bytes = s.ValueOrDie(); return true; case gfx::GpuMemoryBuffer::RGBX_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return false; } diff --git a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc index 38667e5..145b3e6 100644 --- a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc +++ b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc @@ -96,6 +96,7 @@ SurfaceFactoryOzone::BufferFormat GetOzoneFormatFor( case gfx::GpuMemoryBuffer::DXT5: case gfx::GpuMemoryBuffer::ETC1: case gfx::GpuMemoryBuffer::BGRA_8888: + case gfx::GpuMemoryBuffer::YUV_420: NOTREACHED(); return SurfaceFactoryOzone::RGBA_8888; } |