268 lines
8.6 KiB
C++
268 lines
8.6 KiB
C++
#include "include/dvr/dvr_hardware_composer_client.h"
|
|
|
|
#include <android/dvr/IVrComposer.h>
|
|
#include <android/dvr/BnVrComposerCallback.h>
|
|
#include <android/hardware_buffer.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <private/android/AHardwareBufferHelpers.h>
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
struct DvrHwcFrame {
|
|
android::dvr::ComposerView::Frame frame;
|
|
};
|
|
|
|
namespace {
|
|
|
|
class HwcCallback : public android::dvr::BnVrComposerCallback {
|
|
public:
|
|
using CallbackFunction = std::function<int(DvrHwcFrame*)>;
|
|
|
|
explicit HwcCallback(const CallbackFunction& callback);
|
|
~HwcCallback() override;
|
|
|
|
// Reset the callback. This needs to be done early to avoid use after free
|
|
// accesses from binder thread callbacks.
|
|
void Shutdown();
|
|
|
|
std::unique_ptr<DvrHwcFrame> DequeueFrame();
|
|
|
|
private:
|
|
// android::dvr::BnVrComposerCallback:
|
|
android::binder::Status onNewFrame(
|
|
const android::dvr::ParcelableComposerFrame& frame,
|
|
android::dvr::ParcelableUniqueFd* fence) override;
|
|
|
|
// Protects the |callback_| from uses from multiple threads. During shutdown
|
|
// there may be in-flight frame update events. In those cases the callback
|
|
// access needs to be protected otherwise binder threads may access an invalid
|
|
// callback.
|
|
std::mutex mutex_;
|
|
CallbackFunction callback_;
|
|
|
|
HwcCallback(const HwcCallback&) = delete;
|
|
void operator=(const HwcCallback&) = delete;
|
|
};
|
|
|
|
HwcCallback::HwcCallback(const CallbackFunction& callback)
|
|
: callback_(callback) {}
|
|
|
|
HwcCallback::~HwcCallback() {}
|
|
|
|
void HwcCallback::Shutdown() {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
callback_ = nullptr;
|
|
}
|
|
|
|
android::binder::Status HwcCallback::onNewFrame(
|
|
const android::dvr::ParcelableComposerFrame& frame,
|
|
android::dvr::ParcelableUniqueFd* fence) {
|
|
std::lock_guard<std::mutex> guard(mutex_);
|
|
|
|
if (!callback_) {
|
|
fence->set_fence(android::base::unique_fd());
|
|
return android::binder::Status::ok();
|
|
}
|
|
|
|
std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
|
|
dvr_frame->frame = frame.frame();
|
|
|
|
fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
|
|
return android::binder::Status::ok();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
struct DvrHwcClient {
|
|
android::sp<android::dvr::IVrComposer> composer;
|
|
android::sp<HwcCallback> callback;
|
|
};
|
|
|
|
DvrHwcClient* dvrHwcClientCreate(DvrHwcOnFrameCallback callback, void* data) {
|
|
std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
|
|
|
|
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
|
|
client->composer = android::interface_cast<android::dvr::IVrComposer>(
|
|
sm->getService(android::dvr::IVrComposer::SERVICE_NAME()));
|
|
if (!client->composer.get())
|
|
return nullptr;
|
|
|
|
client->callback = new HwcCallback(std::bind(callback, data,
|
|
std::placeholders::_1));
|
|
android::binder::Status status = client->composer->registerObserver(
|
|
client->callback);
|
|
if (!status.isOk())
|
|
return nullptr;
|
|
|
|
return client.release();
|
|
}
|
|
|
|
void dvrHwcClientDestroy(DvrHwcClient* client) {
|
|
client->composer->clearObserver();
|
|
|
|
// NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
|
|
// shared pointer that could be referenced from a binder thread. But the
|
|
// client callback isn't valid past this calls so that needs to be reset.
|
|
client->callback->Shutdown();
|
|
|
|
delete client;
|
|
}
|
|
|
|
void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
|
|
delete frame;
|
|
}
|
|
|
|
DvrHwcDisplay dvrHwcFrameGetDisplayId(DvrHwcFrame* frame) {
|
|
return frame->frame.display_id;
|
|
}
|
|
|
|
int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) {
|
|
return frame->frame.display_width;
|
|
}
|
|
|
|
int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) {
|
|
return frame->frame.display_height;
|
|
}
|
|
|
|
bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) {
|
|
return frame->frame.removed;
|
|
}
|
|
|
|
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
|
|
return frame->frame.layers.size();
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetActiveConfig(DvrHwcFrame* frame) {
|
|
return static_cast<uint32_t>(frame->frame.active_config);
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetColorMode(DvrHwcFrame* frame) {
|
|
return static_cast<uint32_t>(frame->frame.color_mode);
|
|
}
|
|
|
|
void dvrHwcFrameGetColorTransform(DvrHwcFrame* frame, float* out_matrix,
|
|
int32_t* out_hint) {
|
|
*out_hint = frame->frame.color_transform_hint;
|
|
memcpy(out_matrix, frame->frame.color_transform,
|
|
sizeof(frame->frame.color_transform));
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetPowerMode(DvrHwcFrame* frame) {
|
|
return static_cast<uint32_t>(frame->frame.power_mode);
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetVsyncEnabled(DvrHwcFrame* frame) {
|
|
return static_cast<uint32_t>(frame->frame.vsync_enabled);
|
|
}
|
|
|
|
DvrHwcLayer dvrHwcFrameGetLayerId(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].id;
|
|
}
|
|
|
|
AHardwareBuffer* dvrHwcFrameGetLayerBuffer(DvrHwcFrame* frame,
|
|
size_t layer_index) {
|
|
AHardwareBuffer* buffer = android::AHardwareBuffer_from_GraphicBuffer(
|
|
frame->frame.layers[layer_index].buffer.get());
|
|
AHardwareBuffer_acquire(buffer);
|
|
return buffer;
|
|
}
|
|
|
|
int dvrHwcFrameGetLayerFence(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].fence->dup();
|
|
}
|
|
|
|
DvrHwcRecti dvrHwcFrameGetLayerDisplayFrame(DvrHwcFrame* frame,
|
|
size_t layer_index) {
|
|
return DvrHwcRecti{
|
|
frame->frame.layers[layer_index].display_frame.left,
|
|
frame->frame.layers[layer_index].display_frame.top,
|
|
frame->frame.layers[layer_index].display_frame.right,
|
|
frame->frame.layers[layer_index].display_frame.bottom,
|
|
};
|
|
}
|
|
|
|
DvrHwcRectf dvrHwcFrameGetLayerCrop(DvrHwcFrame* frame, size_t layer_index) {
|
|
return DvrHwcRectf{
|
|
frame->frame.layers[layer_index].crop.left,
|
|
frame->frame.layers[layer_index].crop.top,
|
|
frame->frame.layers[layer_index].crop.right,
|
|
frame->frame.layers[layer_index].crop.bottom,
|
|
};
|
|
}
|
|
|
|
DvrHwcBlendMode dvrHwcFrameGetLayerBlendMode(DvrHwcFrame* frame,
|
|
size_t layer_index) {
|
|
return static_cast<DvrHwcBlendMode>(
|
|
frame->frame.layers[layer_index].blend_mode);
|
|
}
|
|
|
|
float dvrHwcFrameGetLayerAlpha(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].alpha;
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerType(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].type;
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerApplicationId(DvrHwcFrame* frame,
|
|
size_t layer_index) {
|
|
return frame->frame.layers[layer_index].app_id;
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerZOrder(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].z_order;
|
|
}
|
|
|
|
void dvrHwcFrameGetLayerCursor(DvrHwcFrame* frame, size_t layer_index,
|
|
int32_t* out_x, int32_t* out_y) {
|
|
*out_x = frame->frame.layers[layer_index].cursor_x;
|
|
*out_y = frame->frame.layers[layer_index].cursor_y;
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerTransform(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].transform;
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerDataspace(DvrHwcFrame* frame, size_t layer_index) {
|
|
return frame->frame.layers[layer_index].dataspace;
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerColor(DvrHwcFrame* frame, size_t layer_index) {
|
|
const auto& color = frame->frame.layers[layer_index].color;
|
|
return color.r | (static_cast<uint32_t>(color.g) << 8) |
|
|
(static_cast<uint32_t>(color.b) << 16) |
|
|
(static_cast<uint32_t>(color.a) << 24);
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerNumVisibleRegions(DvrHwcFrame* frame,
|
|
size_t layer_index) {
|
|
return frame->frame.layers[layer_index].visible_regions.size();
|
|
}
|
|
|
|
DvrHwcRecti dvrHwcFrameGetLayerVisibleRegion(DvrHwcFrame* frame,
|
|
size_t layer_index, size_t index) {
|
|
return DvrHwcRecti{
|
|
frame->frame.layers[layer_index].visible_regions[index].left,
|
|
frame->frame.layers[layer_index].visible_regions[index].top,
|
|
frame->frame.layers[layer_index].visible_regions[index].right,
|
|
frame->frame.layers[layer_index].visible_regions[index].bottom,
|
|
};
|
|
}
|
|
|
|
uint32_t dvrHwcFrameGetLayerNumDamagedRegions(DvrHwcFrame* frame,
|
|
size_t layer_index) {
|
|
return frame->frame.layers[layer_index].damaged_regions.size();
|
|
}
|
|
|
|
DvrHwcRecti dvrHwcFrameGetLayerDamagedRegion(DvrHwcFrame* frame,
|
|
size_t layer_index, size_t index) {
|
|
return DvrHwcRecti{
|
|
frame->frame.layers[layer_index].damaged_regions[index].left,
|
|
frame->frame.layers[layer_index].damaged_regions[index].top,
|
|
frame->frame.layers[layer_index].damaged_regions[index].right,
|
|
frame->frame.layers[layer_index].damaged_regions[index].bottom,
|
|
};
|
|
}
|