| // Copyright 2014 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gpu/command_buffer/client/internal/mappable_buffer_native_pixmap.h" | |
| #include <utility> | |
| #include "base/functional/bind.h" | |
| #include "base/logging.h" | |
| #include "base/memory/ptr_util.h" | |
| #include "build/build_config.h" | |
| #include "components/viz/common/resources/shared_image_format_utils.h" | |
| #include "ui/gfx/buffer_types.h" | |
| #include "ui/gfx/buffer_usage_util.h" | |
| #include "ui/gfx/client_native_pixmap_factory.h" | |
| #include "ui/gfx/native_pixmap.h" | |
| #include "ui/ozone/public/ozone_platform.h" | |
| #include "ui/ozone/public/surface_factory_ozone.h" | |
| namespace gpu { | |
| namespace { | |
| void FreeNativePixmapForTesting( | |
| scoped_refptr<gfx::NativePixmap> native_pixmap) { | |
| // Nothing to do here. |native_pixmap| will be freed when this function | |
| // returns and reference count drops to 0. | |
| } | |
| } // namespace | |
| MappableBufferNativePixmap::MappableBufferNativePixmap( | |
| const gfx::Size& size, | |
| viz::SharedImageFormat format, | |
| std::unique_ptr<gfx::ClientNativePixmap> pixmap) | |
| : size_(size), format_(format), pixmap_(std::move(pixmap)) {} | |
| MappableBufferNativePixmap::~MappableBufferNativePixmap() { | |
| #if DCHECK_IS_ON() | |
| { | |
| base::AutoLock auto_lock(map_lock_); | |
| DCHECK_EQ(map_count_, 0u); | |
| } | |
| #endif | |
| } | |
| void MappableBufferNativePixmap::AssertMapped() { | |
| #if DCHECK_IS_ON() | |
| base::AutoLock auto_lock(map_lock_); | |
| DCHECK_GT(map_count_, 0u); | |
| #endif | |
| } | |
| std::unique_ptr<MappableBufferNativePixmap> | |
| MappableBufferNativePixmap::CreateFromHandle( | |
| gfx::ClientNativePixmapFactory* client_native_pixmap_factory, | |
| gfx::GpuMemoryBufferHandle handle, | |
| const gfx::Size& size, | |
| viz::SharedImageFormat format, | |
| gfx::BufferUsage usage) { | |
| std::unique_ptr<gfx::ClientNativePixmap> native_pixmap = | |
| client_native_pixmap_factory->ImportFromHandle( | |
| std::move(handle).native_pixmap_handle(), size, format, usage); | |
| if (!native_pixmap) { | |
| return nullptr; | |
| } | |
| return base::WrapUnique( | |
| new MappableBufferNativePixmap(size, format, std::move(native_pixmap))); | |
| } | |
| // static | |
| base::OnceClosure MappableBufferNativePixmap::AllocateForTesting( | |
| const gfx::Size& size, | |
| viz::SharedImageFormat format, | |
| gfx::BufferUsage usage, | |
| gfx::GpuMemoryBufferHandle* handle) { | |
| scoped_refptr<gfx::NativePixmap> pixmap; | |
| pixmap = ui::OzonePlatform::GetInstance() | |
| ->GetSurfaceFactoryOzone() | |
| ->CreateNativePixmap(gfx::kNullAcceleratedWidget, nullptr, size, | |
| format, usage); | |
| if (!pixmap) { | |
| // https://crrev.com/c/5348599 | |
| // In some format + usage combination the pixmap may be null. For example, | |
| // YUV_420_BIPLANAR + SCANOUT_CAMERA_READ_WRITE may fail to allocate because | |
| // only some of platform supports that. | |
| LOG(WARNING) << "Failed to allocate pixmap " << format.ToString() << " + " | |
| << gfx::BufferUsageToString(usage); | |
| } else { | |
| *handle = gfx::GpuMemoryBufferHandle(pixmap->ExportHandle()); | |
| } | |
| // It's safe to bind FreeNativePixmapForTesting even if pixmap is not created | |
| // as it does nothing with the pixmap. See the comment in | |
| // FreeNativePixmapForTesting for more details. | |
| return base::BindOnce(&FreeNativePixmapForTesting, pixmap); | |
| } | |
| bool MappableBufferNativePixmap::Map() { | |
| base::AutoLock auto_lock(map_lock_); | |
| if (map_count_++) { | |
| return true; | |
| } | |
| if (format_.NumberOfPlanes() != | |
| static_cast<int>(pixmap_->GetNumberOfPlanes())) { | |
| // RGBX8888 and BGR_565 allocates 2 planes while the gfx function returns 1 | |
| LOG(WARNING) << "Mismatched plane count " << format_.ToString() | |
| << " expected " << format_.NumberOfPlanes() << " value " | |
| << pixmap_->GetNumberOfPlanes(); | |
| } | |
| if (!pixmap_->Map()) { | |
| --map_count_; | |
| return false; | |
| } | |
| return true; | |
| } | |
| base::span<uint8_t> MappableBufferNativePixmap::memory(size_t plane) { | |
| AssertMapped(); | |
| return pixmap_->GetMemoryAsSpan(plane); | |
| } | |
| void MappableBufferNativePixmap::Unmap() { | |
| base::AutoLock auto_lock(map_lock_); | |
| DCHECK_GT(map_count_, 0u); | |
| if (--map_count_) { | |
| return; | |
| } | |
| pixmap_->Unmap(); | |
| } | |
| int MappableBufferNativePixmap::stride(size_t plane) const { | |
| // The caller is responsible for ensuring that |plane| is within bounds. | |
| CHECK_LT(plane, pixmap_->GetNumberOfPlanes()); | |
| return pixmap_->GetStride(plane); | |
| } | |
| gfx::GpuMemoryBufferType MappableBufferNativePixmap::GetType() const { | |
| return gfx::NATIVE_PIXMAP; | |
| } | |
| gfx::GpuMemoryBufferHandle MappableBufferNativePixmap::CloneHandle() const { | |
| gfx::GpuMemoryBufferHandle handle(pixmap_->CloneHandleForIPC()); | |
| return handle; | |
| } | |
| void MappableBufferNativePixmap::MapAsync( | |
| base::OnceCallback<void(bool)> callback) { | |
| std::move(callback).Run(Map()); | |
| } | |
| bool MappableBufferNativePixmap::AsyncMappingIsNonBlocking() const { | |
| return false; | |
| } | |
| } // namespace gpu |