nvnflinger: Implement reference counting for binder objects

Implements proper reference counting for binder objects based on the official
documentation. This adds both weak and strong reference counting support to
the IBinder interface and its implementations (BufferQueueProducer and
BufferQueueConsumer).

The implementation follows the documented behavior where:
- type 0 affects weak references
- type 1 affects strong references
- During initialization: {addval=1, type=0} followed by {addval=1, type=1}
- For onFirstRef: {addval=1, type=1}
- For onLastStrongRef: {addval=-1, type=1}

Reference counters are implemented using std::atomic to ensure thread safety.

REFS: switchbrew.org/wiki/Nvnflinger_services#AdjustRefcount
This commit is contained in:
Zephyron 2025-01-26 14:21:36 +10:00
parent a6063bbd64
commit a5d62fa4ec
4 changed files with 56 additions and 1 deletions

View file

@ -26,6 +26,24 @@ public:
virtual void Transact(u32 code, std::span<const u8> parcel_data, std::span<u8> parcel_reply,
u32 flags) = 0;
virtual Kernel::KReadableEvent* GetNativeHandle(u32 type_id) = 0;
virtual void AdjustWeakRefcount(s32 addval) = 0;
virtual void AdjustStrongRefcount(s32 addval) = 0;
};
class Binder {
public:
void AdjustWeakRefcount(s32 addval) {
m_weak_ref_count += addval;
}
void AdjustStrongRefcount(s32 addval) {
m_strong_ref_count += addval;
}
private:
std::atomic<s32> m_weak_ref_count{};
std::atomic<s32> m_strong_ref_count{};
};
} // namespace Service::android

View file

@ -8,6 +8,7 @@
#include <chrono>
#include <memory>
#include <atomic>
#include "common/common_types.h"
#include "core/hle/service/nvnflinger/binder.h"
@ -36,9 +37,19 @@ public:
Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
void AdjustWeakRefcount(s32 addval) override {
m_weak_ref_count += addval;
}
void AdjustStrongRefcount(s32 addval) override {
m_strong_ref_count += addval;
}
private:
std::shared_ptr<BufferQueueCore> core;
BufferQueueDefs::SlotsType& slots;
std::atomic<s32> m_weak_ref_count{};
std::atomic<s32> m_strong_ref_count{};
};
} // namespace Service::android

View file

@ -9,6 +9,7 @@
#include <condition_variable>
#include <memory>
#include <mutex>
#include <atomic>
#include "common/common_funcs.h"
#include "core/hle/service/nvdrv/nvdata.h"
@ -52,6 +53,14 @@ public:
Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
void AdjustWeakRefcount(s32 addval) override {
m_weak_ref_count += addval;
}
void AdjustStrongRefcount(s32 addval) override {
m_strong_ref_count += addval;
}
public:
Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
Status SetBufferCount(s32 buffer_count);
@ -87,6 +96,8 @@ private:
std::condition_variable_any callback_condition;
Service::Nvidia::NvCore::NvMap& nvmap;
std::atomic<s32> m_weak_ref_count{};
std::atomic<s32> m_strong_ref_count{};
};
} // namespace Service::android

View file

@ -5,6 +5,7 @@
#include "core/hle/service/nvnflinger/binder.h"
#include "core/hle/service/nvnflinger/hos_binder_driver.h"
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include <atomic>
namespace Service::Nvnflinger {
@ -40,7 +41,21 @@ Result IHOSBinderDriver::TransactParcel(s32 binder_id, u32 transaction_id,
}
Result IHOSBinderDriver::AdjustRefcount(s32 binder_id, s32 addval, s32 type) {
LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={}, type={}", binder_id, addval, type);
LOG_DEBUG(Service_VI, "called id={}, addval={}, type={}", binder_id, addval, type);
const auto binder = m_server->TryGetBinder(binder_id);
R_SUCCEED_IF(binder == nullptr);
// type 0 = weak reference, type 1 = strong reference
if (type == 0) {
binder->AdjustWeakRefcount(addval);
} else if (type == 1) {
binder->AdjustStrongRefcount(addval);
} else {
LOG_ERROR(Service_VI, "Invalid refcount type {}", type);
R_THROW(Kernel::ResultInvalidArgument);
}
R_SUCCEED();
}