blob: 63a28e00ecc3ea54544fbf463b259ad3f8c2e96c [file] [log] [blame] [edit]
// Copyright 2023 The Chromium Authors
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SCOPED_BO_MAPPING_FACTORY_H_
#define SCOPED_BO_MAPPING_FACTORY_H_
#include <gbm.h>
#include <memory>
#include <mutex>
#include <vector>
#include "base/logging.h"
#include "base/scoped_fd.h"
namespace libvafake {
struct GbmDeviceDeleter {
void operator()(gbm_device* device);
};
using ScopedGbmDevice = std::unique_ptr<gbm_device, GbmDeviceDeleter>;
class ScopedBOMappingFactory;
// ScopedBOMapping tracks the CPU mapping of a minigbm Buffer Object (BO).
// Upon destruction, it unmaps and destroys the Buffer Object.
//
// Notes:
//
// - Only a ScopedBOMappingFactory can create valid ScopedBOMapping instances.
// Upon destruction, the ScopedBOMapping requests the ScopedBOMappingFactory
// to unmap and destroy the Buffer Object. This is done to ensure that the GBM
// device is protected from concurrent operations on multiple threads.
// Therefore, the ScopedBOMappingFactory that creates a ScopedBOMapping must
// outlive it.
//
// - ScopedBOMapping instances can be used from any thread, but they are NOT
// thread-safe, i.e., access to them must be synchronized externally.
// Additionally, access to different ScopedBOMappings that refer to the same
// dma-buf must also be synchronized externally.
class ScopedBOMapping {
public:
// A ScopedAccess can be used to ensure cache-coherent CPU read/write access
// to a Buffer Object mapping. The intended usage is as follows:
//
// ScopedBOMapping mapping = factory.Create(import_data);
// {
// const auto access = mapping.BeginAccess();
// /* Read/write using access.GetData() and access.GetStride() */
// }
//
// ScopedAccess instances themselves are thread-safe but:
//
// - Concurrent reads/writes to the mapped data must be synchronized
// externally.
//
// - Different ScopedAccess instances corresponding to the same buffer object
// must be synchronized externally.
//
// Note: a ScopedBOMapping must outlive any ScopedAccess instances produced by
// it.
class ScopedAccess {
public:
// Not copyable nor movable (move ctors are deleted by default).
ScopedAccess(const ScopedAccess&) = delete;
ScopedAccess& operator=(const ScopedAccess&) = delete;
~ScopedAccess();
uint8_t* GetData(size_t plane) const;
uint32_t GetStride(size_t plane) const;
private:
// Only ScopedBOMapping should be able to create ScopedAccess instances.
friend class ScopedBOMapping;
explicit ScopedAccess(const ScopedBOMapping& mapping);
const ScopedBOMapping& mapping_;
};
// Creates an invalid ScopedBOMapping.
ScopedBOMapping();
// Not copyable but movable (the copy ctors are deleted by default).
ScopedBOMapping(ScopedBOMapping&& other);
ScopedBOMapping& operator=(ScopedBOMapping&& other);
~ScopedBOMapping();
bool IsValid() const { return !!scoped_bo_mapping_factory_; }
explicit operator bool() const { return IsValid(); }
ScopedAccess BeginAccess() const;
private:
// Contains metadata for each element of a plane retrieved from minigbm.
struct Plane {
Plane(uint32_t stride, void* addr, void* mmap_data, int prime_fd);
Plane(Plane&& other);
Plane& operator=(Plane&& other);
~Plane();
uint32_t stride;
void* addr;
void* mmap_data;
base::ScopedFD prime_fd;
};
// Needed so that GBMDeviceHolder can create ScopedBOMappings.
friend class ScopedBOMappingFactory;
ScopedBOMapping(ScopedBOMappingFactory* scoped_bo_mapping_factory,
std::vector<Plane> planes,
struct gbm_bo* bo_import);
ScopedBOMappingFactory* scoped_bo_mapping_factory_;
std::vector<Plane> planes_;
struct gbm_bo* bo_import_;
};
// A ScopedBOMappingFactory provides thread-safe access to minigbm in order to
// import dma-bufs and map them for CPU access.
//
// ScopedBOMappingFactory instances are thread-safe.
class ScopedBOMappingFactory {
public:
explicit ScopedBOMappingFactory(int drm_fd);
ScopedBOMappingFactory(const ScopedBOMappingFactory&) = delete;
ScopedBOMappingFactory& operator=(const ScopedBOMappingFactory&) = delete;
~ScopedBOMappingFactory();
// Imports and maps the dma-buf referenced by |import_data|. This method
// always returns a valid mapping. If the dma-buf can't be imported, it
// crashes.
ScopedBOMapping Create(gbm_import_fd_modifier_data import_data);
private:
// Needed so that the ScopedBOMapping can call UnmapAndDestroyBufferObject().
friend class ScopedBOMapping;
// Unmaps all the |planes| of the buffer object referenced by |bo_import|.
void UnmapAndDestroyBufferObject(std::vector<ScopedBOMapping::Plane> planes,
struct gbm_bo* bo_import);
std::mutex lock_;
const ScopedGbmDevice gbm_device_;
};
} // namespace libvafake
#endif // SCOPED_BO_MAPPING_FACTORY_H_