blob: 20541a69a5e4cf63c05aba8038738a332a173349 [file] [log] [blame]
#ifndef ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
#define ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
#include <assert.h>
#include <tuple>
#include <libbroadcastring/broadcast_ring.h>
#include <private/dvr/display_client.h>
namespace android {
namespace dvr {
// The buffer usage type for mapped shared buffers.
enum class CPUUsageMode { READ_OFTEN, READ_RARELY, WRITE_OFTEN, WRITE_RARELY };
// Holds the memory for the mapped shared buffer. Unlocks and releases the
// underlying IonBuffer in destructor.
class CPUMappedBuffer {
public:
// This constructor will create a display client and get the buffer from it.
CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode);
// If you already have the IonBuffer, use this. It will take ownership.
CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode);
// Use this if you do not want to take ownership.
CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode);
~CPUMappedBuffer();
// Getters.
size_t Size() const { return size_; }
void* Address() const { return address_; }
bool IsMapped() const { return Address() != nullptr; }
// Attempt mapping this buffer to the CPU addressable space.
// This will create a display client and see if the buffer exists.
// If the buffer has not been setup yet, you will need to try again later.
void TryMapping();
protected:
// The memory area if we managed to map it.
size_t size_ = 0;
void* address_ = nullptr;
// If we are polling the display client, the buffer key here.
DvrGlobalBufferKey buffer_key_;
// If we just own the IonBuffer outright, it's here.
std::unique_ptr<IonBuffer> owned_buffer_ = nullptr;
// The last time we connected to the display service.
int64_t last_display_service_connection_ns_ = 0;
// If we do not own the IonBuffer, it's here
IonBuffer* buffer_ = nullptr;
// The usage mode.
CPUUsageMode usage_mode_ = CPUUsageMode::READ_OFTEN;
};
// Represents a broadcast ring inside a mapped shared memory buffer.
// If has the same set of constructors as CPUMappedBuffer.
// The template argument is the concrete BroadcastRing class that this buffer
// holds.
template <class RingType>
class CPUMappedBroadcastRing : public CPUMappedBuffer {
public:
CPUMappedBroadcastRing(DvrGlobalBufferKey key, CPUUsageMode mode)
: CPUMappedBuffer(key, mode) {}
CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode)
: CPUMappedBuffer(std::move(buffer), mode) {}
CPUMappedBroadcastRing(IonBuffer* buffer, CPUUsageMode mode)
: CPUMappedBuffer(buffer, mode) {}
// Helper function for publishing records in the ring.
void Publish(const typename RingType::Record& record) {
assert((usage_mode_ == CPUUsageMode::WRITE_OFTEN) ||
(usage_mode_ == CPUUsageMode::WRITE_RARELY));
auto ring = Ring();
if (ring) {
ring->Put(record);
}
}
// Helper function for getting records from the ring.
// Returns true if we were able to retrieve the latest.
bool GetNewest(typename RingType::Record* record) {
assert((usage_mode_ == CPUUsageMode::READ_OFTEN) ||
(usage_mode_ == CPUUsageMode::READ_RARELY));
auto ring = Ring();
if (ring) {
return ring->GetNewest(&sequence_, record);
}
return false;
}
// Try obtaining the ring. If the named buffer has not been created yet, it
// will return nullptr.
RingType* Ring() {
// No ring created yet?
if (ring_ == nullptr) {
// Not mapped the memory yet?
if (IsMapped() == false) {
TryMapping();
}
// If have the memory mapped, allocate the ring.
if (IsMapped()) {
switch (usage_mode_) {
case CPUUsageMode::READ_OFTEN:
case CPUUsageMode::READ_RARELY: {
RingType ring;
bool import_ok;
std::tie(ring, import_ok) = RingType::Import(address_, size_);
if (import_ok) {
ring_ = std::make_unique<RingType>(ring);
}
} break;
case CPUUsageMode::WRITE_OFTEN:
case CPUUsageMode::WRITE_RARELY:
ring_ =
std::make_unique<RingType>(RingType::Create(address_, size_));
break;
}
}
}
return ring_.get();
}
protected:
std::unique_ptr<RingType> ring_ = nullptr;
uint32_t sequence_ = 0;
};
} // namespace dvr
} // namespace android
#endif // ANDROID_DVR_SHARED_BUFFER_HELPERS_H_