mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-26 17:32:39 +00:00
[gpu] Adjustments on the frame composer
This commit is contained in:
@@ -94,6 +94,10 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
|
|||||||
Common::ADPF::BeginFrameWork();
|
Common::ADPF::BeginFrameWork();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nvdisp_disp0::WaitForComposite() {
|
||||||
|
system.GPU().WaitForComposite();
|
||||||
|
}
|
||||||
|
|
||||||
Kernel::KEvent* nvdisp_disp0::QueryEvent(u32 event_id) {
|
Kernel::KEvent* nvdisp_disp0::QueryEvent(u32 event_id) {
|
||||||
LOG_CRITICAL(Service_NVDRV, "Unknown DISP Event {}", event_id);
|
LOG_CRITICAL(Service_NVDRV, "Unknown DISP Event {}", event_id);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ public:
|
|||||||
/// Performs a screen flip, compositing each buffer.
|
/// Performs a screen flip, compositing each buffer.
|
||||||
void Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers);
|
void Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers);
|
||||||
|
|
||||||
|
void WaitForComposite();
|
||||||
|
|
||||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
|
|||||||
// Set default speed limit to 100%.
|
// Set default speed limit to 100%.
|
||||||
*out_speed_scale = 1.0f;
|
*out_speed_scale = 1.0f;
|
||||||
|
|
||||||
|
// The composition queued last frame reads guest memory on the GPU thread, so its framebuffers
|
||||||
|
// may only go back to the guest once it has run.
|
||||||
|
nvdisp.WaitForComposite();
|
||||||
|
this->ReleaseFramebuffersLocked(display);
|
||||||
|
|
||||||
// If no layers are available, skip the logic.
|
// If no layers are available, skip the logic.
|
||||||
bool any_visible = false;
|
bool any_visible = false;
|
||||||
for (auto& layer : display.stack.layers) {
|
for (auto& layer : display.stack.layers) {
|
||||||
@@ -158,55 +163,30 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
|
|||||||
nvdisp.Composite(composition_stack);
|
nvdisp.Composite(composition_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batch framebuffer releases, instead of one-into-one.
|
|
||||||
std::vector<std::pair<Layer*, Framebuffer*>> to_release;
|
|
||||||
for (auto& [layer_id, framebuffer] : m_framebuffers) {
|
|
||||||
if (!framebuffer.is_acquired)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto layer = display.stack.FindLayer(layer_id);
|
|
||||||
if (!layer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Overlay layers always release after every compose
|
|
||||||
// Non-overlay layers release based on their swap interval
|
|
||||||
if (layer->is_overlay || framebuffer.release_frame_number <= m_frame_number) {
|
|
||||||
to_release.emplace_back(layer.get(), &framebuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& [layer, framebuffer] : to_release) {
|
|
||||||
layer->buffer_item_consumer->ReleaseBuffer(framebuffer->item, android::Fence::NoFence());
|
|
||||||
framebuffer->is_acquired = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance by 1 frame (60 FPS compositing)
|
// Advance by 1 frame (60 FPS compositing)
|
||||||
m_frame_number += 1;
|
m_frame_number += 1;
|
||||||
|
|
||||||
// Release any necessary framebuffers (non-overlay layers only, as overlays are already released above).
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HardwareComposer::ReleaseFramebuffersLocked(Display& display) {
|
||||||
for (auto& [layer_id, framebuffer] : m_framebuffers) {
|
for (auto& [layer_id, framebuffer] : m_framebuffers) {
|
||||||
if (!framebuffer.is_acquired) {
|
if (!framebuffer.is_acquired) {
|
||||||
// Already released.
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (framebuffer.release_frame_number > m_frame_number) {
|
const auto layer = display.stack.FindLayer(layer_id);
|
||||||
|
if (!layer) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
|
if (!layer->is_overlay && framebuffer.release_frame_number > m_frame_number) {
|
||||||
// Skip overlay layers as they were already released above
|
continue;
|
||||||
if (layer->is_overlay) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: support release fence
|
|
||||||
// This is needed to prevent screen tearing
|
|
||||||
layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
|
|
||||||
framebuffer.is_acquired = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
|
||||||
|
framebuffer.is_acquired = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) {
|
void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_id) {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer);
|
bool TryAcquireFramebufferLocked(Layer& layer, Framebuffer& framebuffer);
|
||||||
CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id);
|
CacheStatus CacheFramebufferLocked(Layer& layer, ConsumerId consumer_id);
|
||||||
|
void ReleaseFramebuffersLocked(Display& display);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvnflinger
|
} // namespace Service::Nvnflinger
|
||||||
|
|||||||
+42
-22
@@ -10,6 +10,7 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
@@ -129,7 +130,7 @@ struct GPU::Impl {
|
|||||||
[[nodiscard]] u64 RequestSyncOperation(Func&& action) {
|
[[nodiscard]] u64 RequestSyncOperation(Func&& action) {
|
||||||
std::unique_lock lck{sync_request_mutex};
|
std::unique_lock lck{sync_request_mutex};
|
||||||
const u64 fence = ++last_sync_fence;
|
const u64 fence = ++last_sync_fence;
|
||||||
sync_requests.emplace_back(action);
|
sync_requests.emplace_back(std::forward<Func>(action));
|
||||||
return fence;
|
return fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,9 +233,9 @@ struct GPU::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, std::vector<Service::Nvidia::NvFence>&& fences) {
|
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers, std::vector<Service::Nvidia::NvFence>&& fences) {
|
||||||
size_t num_fences{fences.size()};
|
const size_t num_fences{fences.size()};
|
||||||
size_t current_request_counter{};
|
size_t current_request_counter{};
|
||||||
{
|
if (num_fences != 0) {
|
||||||
std::unique_lock<std::mutex> lk(request_swap_mutex);
|
std::unique_lock<std::mutex> lk(request_swap_mutex);
|
||||||
if (free_swap_counters.empty()) {
|
if (free_swap_counters.empty()) {
|
||||||
current_request_counter = request_swap_counters.size();
|
current_request_counter = request_swap_counters.size();
|
||||||
@@ -245,27 +246,41 @@ struct GPU::Impl {
|
|||||||
free_swap_counters.pop_front();
|
free_swap_counters.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto wait_fence = RequestSyncOperation([this, current_request_counter, &layers, &fences, num_fences] {
|
pending_composite_fence = RequestSyncOperation(
|
||||||
auto& syncpoint_manager = system.Host1x().GetSyncpointManager();
|
[this, current_request_counter, num_fences, layers = std::move(layers),
|
||||||
if (num_fences == 0) {
|
fences = std::move(fences)] {
|
||||||
renderer->Composite(layers);
|
if (num_fences == 0) {
|
||||||
}
|
renderer->Composite(layers);
|
||||||
const auto executer = [this, current_request_counter, layers_copy = layers]() {
|
return;
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lk(request_swap_mutex);
|
|
||||||
if (--request_swap_counters[current_request_counter] != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
free_swap_counters.push_back(current_request_counter);
|
|
||||||
}
|
}
|
||||||
renderer->Composite(layers_copy);
|
auto& syncpoint_manager = system.Host1x().GetSyncpointManager();
|
||||||
};
|
const auto executer = [this, current_request_counter, layers]() {
|
||||||
for (size_t i = 0; i < num_fences; i++) {
|
{
|
||||||
syncpoint_manager.RegisterGuestAction(fences[i].id, fences[i].value, executer);
|
std::unique_lock<std::mutex> lk(request_swap_mutex);
|
||||||
}
|
if (--request_swap_counters[current_request_counter] != 0) {
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
free_swap_counters.push_back(current_request_counter);
|
||||||
|
}
|
||||||
|
renderer->Composite(layers);
|
||||||
|
};
|
||||||
|
for (size_t i = 0; i < num_fences; i++) {
|
||||||
|
syncpoint_manager.RegisterGuestAction(fences[i].id, fences[i].value, executer);
|
||||||
|
}
|
||||||
|
});
|
||||||
gpu_thread.TickGPU(is_async);
|
gpu_thread.TickGPU(is_async);
|
||||||
WaitForSyncOperation(wait_fence);
|
}
|
||||||
|
|
||||||
|
void WaitForComposite() {
|
||||||
|
const u64 fence = pending_composite_fence;
|
||||||
|
if (fence == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pending_composite_fence = 0;
|
||||||
|
if (shutting_down.load(std::memory_order_relaxed)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WaitForSyncOperation(fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> GetAppletCaptureBuffer() {
|
std::vector<u8> GetAppletCaptureBuffer() {
|
||||||
@@ -318,6 +333,7 @@ struct GPU::Impl {
|
|||||||
std::deque<size_t> free_swap_counters;
|
std::deque<size_t> free_swap_counters;
|
||||||
std::deque<size_t> request_swap_counters;
|
std::deque<size_t> request_swap_counters;
|
||||||
std::mutex request_swap_mutex;
|
std::mutex request_swap_mutex;
|
||||||
|
u64 pending_composite_fence{};
|
||||||
};
|
};
|
||||||
|
|
||||||
GPU::GPU(Core::System& system, bool is_async, bool use_nvdec)
|
GPU::GPU(Core::System& system, bool is_async, bool use_nvdec)
|
||||||
@@ -435,6 +451,10 @@ void GPU::RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
|
|||||||
impl->RequestComposite(std::move(layers), std::move(fences));
|
impl->RequestComposite(std::move(layers), std::move(fences));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPU::WaitForComposite() {
|
||||||
|
impl->WaitForComposite();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<u8> GPU::GetAppletCaptureBuffer() {
|
std::vector<u8> GPU::GetAppletCaptureBuffer() {
|
||||||
return impl->GetAppletCaptureBuffer();
|
return impl->GetAppletCaptureBuffer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ public:
|
|||||||
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
|
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
|
||||||
std::vector<Service::Nvidia::NvFence>&& fences);
|
std::vector<Service::Nvidia::NvFence>&& fences);
|
||||||
|
|
||||||
|
void WaitForComposite();
|
||||||
|
|
||||||
std::vector<u8> GetAppletCaptureBuffer();
|
std::vector<u8> GetAppletCaptureBuffer();
|
||||||
|
|
||||||
/// Performs any additional setup necessary in order to begin GPU emulation.
|
/// Performs any additional setup necessary in order to begin GPU emulation.
|
||||||
|
|||||||
Reference in New Issue
Block a user