[GPU] Display swap output in the trace viewer

Resolve output is unreliable because resolving may be done to a subregion of a texture and even to 3D textures, and to any color format
This commit is contained in:
Triang3l 2022-07-01 19:50:19 +03:00
parent 28670d8ec2
commit e37e3ef382
12 changed files with 25 additions and 58 deletions

View File

@ -683,6 +683,7 @@ EmulatorWindow::GetGuestOutputPaintEffectForCvarValue(
ui::Presenter::GuestOutputPaintConfig ui::Presenter::GuestOutputPaintConfig
EmulatorWindow::GetGuestOutputPaintConfigForCvars() { EmulatorWindow::GetGuestOutputPaintConfigForCvars() {
ui::Presenter::GuestOutputPaintConfig paint_config; ui::Presenter::GuestOutputPaintConfig paint_config;
paint_config.SetAllowOverscanCutoff(true);
paint_config.SetEffect(GetGuestOutputPaintEffectForCvarValue( paint_config.SetEffect(GetGuestOutputPaintEffectForCvarValue(
cvars::postprocess_scaling_and_sharpening)); cvars::postprocess_scaling_and_sharpening));
paint_config.SetCasAdditionalSharpness( paint_config.SetCasAdditionalSharpness(

View File

@ -916,9 +916,7 @@ bool CommandProcessor::ExecutePacketType3_XE_SWAP(RingBuffer* reader,
uint32_t frontbuffer_height = reader->ReadAndSwap<uint32_t>(); uint32_t frontbuffer_height = reader->ReadAndSwap<uint32_t>();
reader->AdvanceRead((count - 4) * sizeof(uint32_t)); reader->AdvanceRead((count - 4) * sizeof(uint32_t));
if (!ignore_swap_) {
IssueSwap(frontbuffer_ptr, frontbuffer_width, frontbuffer_height); IssueSwap(frontbuffer_ptr, frontbuffer_width, frontbuffer_height);
}
++counter_; ++counter_;
return true; return true;

View File

@ -90,7 +90,6 @@ class CommandProcessor {
virtual void ClearCaches(); virtual void ClearCaches();
void SetIgnoreSwap(bool ignore_swap) { ignore_swap_ = ignore_swap; }
// "Desired" is for the external thread managing the post-processing effect. // "Desired" is for the external thread managing the post-processing effect.
SwapPostEffect GetDesiredSwapPostEffect() const { SwapPostEffect GetDesiredSwapPostEffect() const {
return swap_post_effect_desired_; return swap_post_effect_desired_;
@ -265,8 +264,6 @@ class CommandProcessor {
std::atomic<bool> worker_running_; std::atomic<bool> worker_running_;
kernel::object_ref<kernel::XHostThread> worker_thread_; kernel::object_ref<kernel::XHostThread> worker_thread_;
bool ignore_swap_ = false;
std::queue<std::function<void()>> pending_fns_; std::queue<std::function<void()>> pending_fns_;
// MicroEngine binary from PM4_ME_INIT // MicroEngine binary from PM4_ME_INIT

View File

@ -1718,10 +1718,6 @@ void D3D12CommandProcessor::OnGammaRampPWLValueWritten() {
void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr, void D3D12CommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
uint32_t frontbuffer_width, uint32_t frontbuffer_width,
uint32_t frontbuffer_height) { uint32_t frontbuffer_height) {
// FIXME(Triang3l): frontbuffer_ptr is currently unreliable, in the trace
// player it's set to 0, but it's not needed anyway since the fetch constant
// contains the address.
SCOPE_profile_cpu_f("gpu"); SCOPE_profile_cpu_f("gpu");
ui::Presenter* presenter = graphics_system_->presenter(); ui::Presenter* presenter = graphics_system_->presenter();

View File

@ -89,19 +89,15 @@ void TracePlayer::PlayTrace(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode, TracePlaybackMode playback_mode,
bool clear_caches) { bool clear_caches) {
playing_trace_ = true; playing_trace_ = true;
// Pass a copy of present_last_copy_ to the thread so it's not accessible by
// multiple threads at once.
bool present_last_copy = present_last_copy_;
graphics_system_->command_processor()->CallInThread([=]() { graphics_system_->command_processor()->CallInThread([=]() {
PlayTraceOnThread(trace_data, trace_size, playback_mode, clear_caches, PlayTraceOnThread(trace_data, trace_size, playback_mode, clear_caches);
present_last_copy);
}); });
} }
void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data, void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data,
size_t trace_size, size_t trace_size,
TracePlaybackMode playback_mode, TracePlaybackMode playback_mode,
bool clear_caches, bool present_last_copy) { bool clear_caches) {
auto memory = graphics_system_->memory(); auto memory = graphics_system_->memory();
auto command_processor = graphics_system_->command_processor(); auto command_processor = graphics_system_->command_processor();
@ -109,10 +105,6 @@ void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data,
command_processor->ClearCaches(); command_processor->ClearCaches();
} }
if (present_last_copy) {
command_processor->SetIgnoreSwap(true);
}
playback_percent_ = 0; playback_percent_ = 0;
auto trace_end = trace_data + trace_size; auto trace_end = trace_data + trace_size;
@ -252,11 +244,6 @@ void TracePlayer::PlayTraceOnThread(const uint8_t* trace_data,
playing_trace_ = false; playing_trace_ = false;
if (present_last_copy) {
command_processor->SetIgnoreSwap(false);
command_processor->IssueSwap(0, 1280, 720);
}
playback_event_->Set(); playback_event_->Set();
} }

View File

@ -32,9 +32,6 @@ class TracePlayer : public TraceReader {
TracePlayer(GraphicsSystem* graphics_system); TracePlayer(GraphicsSystem* graphics_system);
GraphicsSystem* graphics_system() const { return graphics_system_; } GraphicsSystem* graphics_system() const { return graphics_system_; }
void SetPresentLastCopy(bool present_last_copy) {
present_last_copy_ = present_last_copy;
}
int current_frame_index() const { return current_frame_index_; } int current_frame_index() const { return current_frame_index_; }
int current_command_index() const { return current_command_index_; } int current_command_index() const { return current_command_index_; }
bool is_playing_trace() const { return playing_trace_; } bool is_playing_trace() const { return playing_trace_; }
@ -53,13 +50,9 @@ class TracePlayer : public TraceReader {
void PlayTrace(const uint8_t* trace_data, size_t trace_size, void PlayTrace(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode, bool clear_caches); TracePlaybackMode playback_mode, bool clear_caches);
void PlayTraceOnThread(const uint8_t* trace_data, size_t trace_size, void PlayTraceOnThread(const uint8_t* trace_data, size_t trace_size,
TracePlaybackMode playback_mode, bool clear_caches, TracePlaybackMode playback_mode, bool clear_caches);
bool present_last_copy);
GraphicsSystem* graphics_system_; GraphicsSystem* graphics_system_;
// Whether to present the results of the latest resolve instead of displaying
// the front buffer from the trace.
bool present_last_copy_ = false;
int current_frame_index_; int current_frame_index_;
int current_command_index_; int current_command_index_;
bool playing_trace_ = false; bool playing_trace_ = false;

View File

@ -114,7 +114,7 @@ bool TraceViewer::Setup() {
// Main display window. // Main display window.
assert_true(app_context().IsInUIThread()); assert_true(app_context().IsInUIThread());
window_ = xe::ui::Window::Create(app_context(), "xenia-gpu-trace-viewer", window_ = xe::ui::Window::Create(app_context(), "xenia-gpu-trace-viewer",
1920, 1200); 1920, 1080);
window_->AddListener(&window_listener_); window_->AddListener(&window_listener_);
window_->AddInputListener(&window_listener_, kZOrderTraceViewerInput); window_->AddInputListener(&window_listener_, kZOrderTraceViewerInput);
if (!window_->Open()) { if (!window_->Open()) {
@ -135,28 +135,27 @@ bool TraceViewer::Setup() {
graphics_system_ = emulator_->graphics_system(); graphics_system_ = emulator_->graphics_system();
player_ = std::make_unique<TracePlayer>(graphics_system_); player_ = std::make_unique<TracePlayer>(graphics_system_);
player_->SetPresentLastCopy(true);
// Setup drawing to the window. // Setup drawing to the window.
xe::ui::GraphicsProvider& graphics_provider = *graphics_system_->provider(); ui::Presenter* presenter = graphics_system_->presenter();
presenter_ = graphics_provider.CreatePresenter(); if (!presenter) {
if (!presenter_) {
XELOGE("Failed to initialize the presenter"); XELOGE("Failed to initialize the presenter");
return false; return false;
} }
xe::ui::GraphicsProvider& graphics_provider = *graphics_system_->provider();
immediate_drawer_ = graphics_provider.CreateImmediateDrawer(); immediate_drawer_ = graphics_provider.CreateImmediateDrawer();
if (!immediate_drawer_) { if (!immediate_drawer_) {
XELOGE("Failed to initialize the immediate drawer"); XELOGE("Failed to initialize the immediate drawer");
return false; return false;
} }
immediate_drawer_->SetPresenter(presenter_.get()); immediate_drawer_->SetPresenter(presenter);
imgui_drawer_ = imgui_drawer_ =
std::make_unique<xe::ui::ImGuiDrawer>(window_.get(), kZOrderImGui); std::make_unique<xe::ui::ImGuiDrawer>(window_.get(), kZOrderImGui);
imgui_drawer_->SetPresenterAndImmediateDrawer(presenter_.get(), imgui_drawer_->SetPresenterAndImmediateDrawer(presenter,
immediate_drawer_.get()); immediate_drawer_.get());
trace_viewer_dialog_ = std::unique_ptr<TraceViewerDialog>( trace_viewer_dialog_ = std::unique_ptr<TraceViewerDialog>(
new TraceViewerDialog(imgui_drawer_.get(), *this)); new TraceViewerDialog(imgui_drawer_.get(), *this));
window_->SetPresenter(presenter_.get()); window_->SetPresenter(presenter);
return true; return true;
} }

View File

@ -21,7 +21,6 @@
#include "xenia/ui/imgui_dialog.h" #include "xenia/ui/imgui_dialog.h"
#include "xenia/ui/imgui_drawer.h" #include "xenia/ui/imgui_drawer.h"
#include "xenia/ui/immediate_drawer.h" #include "xenia/ui/immediate_drawer.h"
#include "xenia/ui/presenter.h"
#include "xenia/ui/window.h" #include "xenia/ui/window.h"
#include "xenia/ui/window_listener.h" #include "xenia/ui/window_listener.h"
#include "xenia/ui/windowed_app.h" #include "xenia/ui/windowed_app.h"
@ -129,7 +128,6 @@ class TraceViewer : public xe::ui::WindowedApp {
GraphicsSystem* graphics_system_ = nullptr; GraphicsSystem* graphics_system_ = nullptr;
std::unique_ptr<TracePlayer> player_; std::unique_ptr<TracePlayer> player_;
std::unique_ptr<xe::ui::Presenter> presenter_;
std::unique_ptr<xe::ui::ImmediateDrawer> immediate_drawer_; std::unique_ptr<xe::ui::ImmediateDrawer> immediate_drawer_;
std::unique_ptr<xe::ui::ImGuiDrawer> imgui_drawer_; std::unique_ptr<xe::ui::ImGuiDrawer> imgui_drawer_;
std::unique_ptr<TraceViewerDialog> trace_viewer_dialog_; std::unique_ptr<TraceViewerDialog> trace_viewer_dialog_;

View File

@ -269,11 +269,6 @@ void VulkanCommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
return; return;
} }
if (!frontbuffer_ptr) {
// Trace viewer does this.
frontbuffer_ptr = last_copy_base_;
}
std::vector<VkCommandBuffer> submit_buffers; std::vector<VkCommandBuffer> submit_buffers;
if (frame_open_) { if (frame_open_) {
// TODO(DrChat): If the setup buffer is empty, don't bother queueing it up. // TODO(DrChat): If the setup buffer is empty, don't bother queueing it up.
@ -1108,9 +1103,6 @@ bool VulkanCommandProcessor::IssueCopy() {
texture->in_flight_fence = current_batch_fence_; texture->in_flight_fence = current_batch_fence_;
// For debugging purposes only (trace viewer)
last_copy_base_ = texture->texture_info.memory.base_address;
if (!frame_open_) { if (!frame_open_) {
BeginFrame(); BeginFrame();
} else if (current_render_state_) { } else if (current_render_state_) {

View File

@ -106,9 +106,6 @@ class VulkanCommandProcessor : public CommandProcessor {
uint32_t coher_base_vc_ = 0; uint32_t coher_base_vc_ = 0;
uint32_t coher_size_vc_ = 0; uint32_t coher_size_vc_ = 0;
// Last copy base address, for debugging only.
uint32_t last_copy_base_ = 0;
bool capturing_ = false; bool capturing_ = false;
bool trace_requested_ = false; bool trace_requested_ = false;
bool cache_clear_requested_ = false; bool cache_clear_requested_ = false;

View File

@ -714,7 +714,8 @@ Presenter::GuestOutputPaintFlow Presenter::GetGuestOutputPaintFlow(
// ratio while stretching throughout the entire surface's width, then limit // ratio while stretching throughout the entire surface's width, then limit
// the Y cropping via letterboxing or stretching along X. // the Y cropping via letterboxing or stretching along X.
uint32_t present_safe_area; uint32_t present_safe_area;
if (cvars::present_safe_area_y > 0 && cvars::present_safe_area_y < 100) { if (config.GetAllowOverscanCutoff() && cvars::present_safe_area_y > 0 &&
cvars::present_safe_area_y < 100) {
present_safe_area = uint32_t(cvars::present_safe_area_y); present_safe_area = uint32_t(cvars::present_safe_area_y);
} else { } else {
present_safe_area = 100; present_safe_area = 100;
@ -756,7 +757,8 @@ Presenter::GuestOutputPaintFlow Presenter::GetGuestOutputPaintFlow(
// aspect ratio while stretching throughout the entire surface's height, // aspect ratio while stretching throughout the entire surface's height,
// then limit the X cropping via letterboxing or stretching along Y. // then limit the X cropping via letterboxing or stretching along Y.
uint32_t present_safe_area; uint32_t present_safe_area;
if (cvars::present_safe_area_x > 0 && cvars::present_safe_area_x < 100) { if (config.GetAllowOverscanCutoff() && cvars::present_safe_area_x > 0 &&
cvars::present_safe_area_x < 100) {
present_safe_area = uint32_t(cvars::present_safe_area_x); present_safe_area = uint32_t(cvars::present_safe_area_x);
} else { } else {
present_safe_area = 100; present_safe_area = 100;

View File

@ -228,6 +228,11 @@ class Presenter {
// In the sharpness setters, min / max with a constant as the first argument // In the sharpness setters, min / max with a constant as the first argument
// also drops NaNs. // also drops NaNs.
bool GetAllowOverscanCutoff() const { return allow_overscan_cutoff_; }
void SetAllowOverscanCutoff(bool new_allow_overscan_cutoff) {
allow_overscan_cutoff_ = new_allow_overscan_cutoff;
}
Effect GetEffect() const { return effect_; } Effect GetEffect() const { return effect_; }
void SetEffect(Effect new_effect) { effect_ = new_effect; } void SetEffect(Effect new_effect) { effect_ = new_effect; }
@ -265,8 +270,10 @@ class Presenter {
void SetDither(bool new_dither) { dither_ = new_dither; } void SetDither(bool new_dither) { dither_ = new_dither; }
private: private:
// Tools, rather than the emulator itself, must use kBilinear as the image // Tools, rather than the emulator itself, must not allow overscan cutoff
// must be as close to the original front buffer as possible. // and must use the kBilinear effect as the image must be as close to the
// original front buffer as possible.
bool allow_overscan_cutoff_ = false;
Effect effect_ = Effect::kBilinear; Effect effect_ = Effect::kBilinear;
float cas_additional_sharpness_ = kCasAdditionalSharpnessDefault; float cas_additional_sharpness_ = kCasAdditionalSharpnessDefault;
uint32_t fsr_max_upsampling_passes_ = kFsrMaxUpscalingPassesMax; uint32_t fsr_max_upsampling_passes_ = kFsrMaxUpscalingPassesMax;