chromium/ui/ozone/platform/flatland/flatland_sysmem_buffer_manager.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/ozone/platform/flatland/flatland_sysmem_buffer_manager.h"

#include <zircon/rights.h>

#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/koid.h"
#include "base/functional/bind.h"
#include "ui/ozone/platform/flatland/flatland_sysmem_buffer_collection.h"

namespace ui {

namespace {

std::string GetProcessName() {
  char name[ZX_MAX_NAME_LEN] = {};
  zx_status_t status =
      zx::process::self()->get_property(ZX_PROP_NAME, name, sizeof(name));
  return (status == ZX_OK) ? std::string(name) : "";
}

}  // namespace

FlatlandSysmemBufferManager::FlatlandSysmemBufferManager(
    FlatlandSurfaceFactory* flatland_surface_factory)
    : flatland_surface_factory_(flatland_surface_factory) {}

FlatlandSysmemBufferManager::~FlatlandSysmemBufferManager() {
  Shutdown();
}

void FlatlandSysmemBufferManager::Initialize(
    fuchsia::sysmem2::AllocatorHandle sysmem_allocator,
    fuchsia::ui::composition::AllocatorHandle flatland_allocator) {
  base::AutoLock auto_lock(collections_lock_);
  DCHECK(collections_.empty());

  DCHECK(!sysmem_allocator_);
  sysmem_allocator_.Bind(std::move(sysmem_allocator));
  sysmem_allocator_->SetDebugClientInfo(
      std::move(fuchsia::sysmem2::AllocatorSetDebugClientInfoRequest{}
                    .set_name(GetProcessName() + "-FlatlandSysmemBufferManager")
                    .set_id(base::GetCurrentProcId())));

  DCHECK(!flatland_allocator_);
  flatland_allocator_.Bind(std::move(flatland_allocator));
  flatland_allocator_.set_error_handler(base::LogFidlErrorAndExitProcess(
      FROM_HERE, "fuchsia::ui::composition::Allocator"));
}

void FlatlandSysmemBufferManager::Shutdown() {
  base::AutoLock auto_lock(collections_lock_);
  DCHECK(collections_.empty());
  sysmem_allocator_ = nullptr;
  flatland_allocator_ = nullptr;
}

scoped_refptr<gfx::NativePixmap>
FlatlandSysmemBufferManager::CreateNativePixmap(VkDevice vk_device,
                                                gfx::Size size,
                                                gfx::BufferFormat format,
                                                gfx::BufferUsage usage) {
  gfx::NativePixmapHandle pixmap_handle;
  zx::eventpair service_handle;
  auto status = zx::eventpair::create(
      0, &pixmap_handle.buffer_collection_handle, &service_handle);
  ZX_DCHECK(status == ZX_OK, status);

  auto collection = base::MakeRefCounted<FlatlandSysmemBufferCollection>();
  if (!collection->Initialize(
          sysmem_allocator_.get(), flatland_allocator_.get(),
          flatland_surface_factory_, std::move(service_handle),
          /*token_channel=*/zx::channel(), size, format, usage, vk_device,
          /*min_buffer_count=*/1, usage == gfx::BufferUsage::SCANOUT)) {
    return nullptr;
  }

  auto result = collection->CreateNativePixmap(std::move(pixmap_handle), size);

  if (result)
    RegisterCollection(collection);

  return result;
}

scoped_refptr<FlatlandSysmemBufferCollection>
FlatlandSysmemBufferManager::ImportSysmemBufferCollection(
    VkDevice vk_device,
    zx::eventpair service_handle,
    zx::channel sysmem_token,
    gfx::Size size,
    gfx::BufferFormat format,
    gfx::BufferUsage usage,
    size_t min_buffer_count,
    bool register_with_flatland_allocator) {
  auto result = base::MakeRefCounted<FlatlandSysmemBufferCollection>();
  if (!result->Initialize(sysmem_allocator_.get(), flatland_allocator_.get(),
                          flatland_surface_factory_, std::move(service_handle),
                          std::move(sysmem_token), size, format, usage,
                          vk_device, min_buffer_count,
                          register_with_flatland_allocator)) {
    return nullptr;
  }
  RegisterCollection(result);
  return result;
}

void FlatlandSysmemBufferManager::RegisterCollection(
    scoped_refptr<FlatlandSysmemBufferCollection> collection) {
  {
    base::AutoLock auto_lock(collections_lock_);
    collections_[collection->id()] = collection;
  }

  collection->AddOnReleasedCallback(
      base::BindOnce(&FlatlandSysmemBufferManager::OnCollectionReleased,
                     base::Unretained(this), collection->id()));
}

scoped_refptr<FlatlandSysmemBufferCollection>
FlatlandSysmemBufferManager::GetCollectionByHandle(const zx::eventpair& token) {
  auto koid = base::GetRelatedKoid(token);
  if (!koid)
    return nullptr;

  base::AutoLock auto_lock(collections_lock_);
  auto it = collections_.find(koid.value());
  return it == collections_.end() ? nullptr : it->second;
}

void FlatlandSysmemBufferManager::OnCollectionReleased(zx_koid_t id) {
  base::AutoLock auto_lock(collections_lock_);
  int erased = collections_.erase(id);
  DCHECK_EQ(erased, 1);
}

}  // namespace ui