[UI] Image post-processing and full presentation/window rework
[GPU] Add FXAA post-processing [UI] Add FidelityFX FSR and CAS post-processing [UI] Add blue noise dithering from 10bpc to 8bpc [GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color [UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event [UI] Allow variable refresh rate (or tearing) [UI] Present the newest frame (restart) on DXGI [UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management [UI] Connect presentation to windows via the Surface class, not native window handles [Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around [Vulkan] Lower the minimum required Vulkan version to 1.0 [UI/GPU] Various cleanup, mainly ComPtr usage [UI] Support per-monitor DPI awareness v2 on Windows [UI] DPI-scale Dear ImGui [UI] Replace the remaining non-detachable window delegates with unified window event and input listeners [UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem [UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing [UI] Add explicit window lifecycle phases [UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback [UI] GTK: Apply the initial size to the drawing area [UI] Limit internal UI frame rate to that of the monitor [UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include "xenia/gpu/texture_info.h"
|
||||
#include "xenia/gpu/texture_util.h"
|
||||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/ui/graphics_util.h"
|
||||
|
||||
// Very prominent in 545407F2.
|
||||
DEFINE_bool(
|
||||
@@ -33,85 +34,10 @@ DEFINE_bool(
|
||||
"for certain games to display the scene graphics).",
|
||||
"GPU");
|
||||
|
||||
DEFINE_bool(
|
||||
present_rescale, true,
|
||||
"Whether to rescale the image, instead of maintaining the original pixel "
|
||||
"size, when presenting to the window. When this is disabled, other "
|
||||
"positioning options are ignored.",
|
||||
"GPU");
|
||||
DEFINE_bool(
|
||||
present_letterbox, true,
|
||||
"Maintain aspect ratio when stretching by displaying bars around the image "
|
||||
"when there's no more overscan area to crop out.",
|
||||
"GPU");
|
||||
// https://github.com/MonoGame/MonoGame/issues/4697#issuecomment-217779403
|
||||
// Using the value from DirectXTK (5% cropped out from each side, thus 90%),
|
||||
// which is not exactly the Xbox One title-safe area, but close, and within the
|
||||
// action-safe area:
|
||||
// https://github.com/microsoft/DirectXTK/blob/1e80a465c6960b457ef9ab6716672c1443a45024/Src/SimpleMath.cpp#L144
|
||||
// XNA TitleSafeArea is 80%, but it's very conservative, designed for CRT, and
|
||||
// is the title-safe area rather than the action-safe area.
|
||||
// 90% is also exactly the fraction of 16:9 height in 16:10.
|
||||
DEFINE_int32(
|
||||
present_safe_area_x, 90,
|
||||
"Percentage of the image width that can be kept when presenting to "
|
||||
"maintain aspect ratio without letterboxing or stretching.",
|
||||
"GPU");
|
||||
DEFINE_int32(
|
||||
present_safe_area_y, 90,
|
||||
"Percentage of the image height that can be kept when presenting to "
|
||||
"maintain aspect ratio without letterboxing or stretching.",
|
||||
"GPU");
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
namespace draw_util {
|
||||
|
||||
int32_t FloatToD3D11Fixed16p8(float f32) {
|
||||
// https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#3.2.4.1%20FLOAT%20-%3E%20Fixed%20Point%20Integer
|
||||
// Early exit tests.
|
||||
// n == NaN || n.unbiasedExponent < -f-1 -> 0 . 0
|
||||
if (!(std::abs(f32) >= 1.0f / 512.0f)) {
|
||||
return 0;
|
||||
}
|
||||
// n >= (2^(i-1)-2^-f) -> 2^(i-1)-1 . 2^f-1
|
||||
if (f32 >= 32768.0f - 1.0f / 256.0f) {
|
||||
return (1 << 23) - 1;
|
||||
}
|
||||
// n <= -2^(i-1) -> -2^(i-1) . 0
|
||||
if (f32 <= -32768.0f) {
|
||||
return -32768 * 256;
|
||||
}
|
||||
uint32_t f32_bits = *reinterpret_cast<const uint32_t*>(&f32);
|
||||
// Copy float32 mantissa bits [22:0] into corresponding bits [22:0] of a
|
||||
// result buffer that has at least 24 bits total storage (before reaching
|
||||
// rounding step further below). This includes one bit for the hidden 1.
|
||||
// Set bit [23] (float32 hidden bit).
|
||||
// Clear bits [31:24].
|
||||
union {
|
||||
int32_t s;
|
||||
uint32_t u;
|
||||
} result;
|
||||
result.u = (f32_bits & ((1 << 23) - 1)) | (1 << 23);
|
||||
// If the sign bit is set in the float32 number (negative), then take the 2's
|
||||
// component of the entire set of bits.
|
||||
if ((f32_bits >> 31) != 0) {
|
||||
result.s = -result.s;
|
||||
}
|
||||
// Final calculation: extraBits = (mantissa - f) - n.unbiasedExponent
|
||||
// (guaranteed to be >= 0).
|
||||
int32_t exponent = int32_t((f32_bits >> 23) & 255) - 127;
|
||||
uint32_t extra_bits = uint32_t(15 - exponent);
|
||||
if (extra_bits) {
|
||||
// Round the 32-bit value to a decimal that is extraBits to the left of
|
||||
// the LSB end, using nearest-even.
|
||||
result.u += (1 << (extra_bits - 1)) - 1 + ((result.u >> extra_bits) & 1);
|
||||
// Shift right by extraBits (sign extending).
|
||||
result.s >>= extra_bits;
|
||||
}
|
||||
return result.s;
|
||||
}
|
||||
|
||||
bool IsRasterizationPotentiallyDone(const RegisterFile& regs,
|
||||
bool primitive_polygonal) {
|
||||
// TODO(Triang3l): Investigate ModeControl::kIgnore better, with respect to
|
||||
@@ -746,7 +672,7 @@ bool GetResolveInfo(const RegisterFile& regs, const Memory& memory,
|
||||
regs.Get<reg::PA_SU_VTX_CNTL>().pix_center ? 0.0f : 0.5f;
|
||||
int32_t vertices_fixed[6];
|
||||
for (size_t i = 0; i < xe::countof(vertices_fixed); ++i) {
|
||||
vertices_fixed[i] = FloatToD3D11Fixed16p8(
|
||||
vertices_fixed[i] = ui::FloatToD3D11Fixed16p8(
|
||||
xenos::GpuSwap(vertices_guest[i], fetch.endian) + half_pixel_offset);
|
||||
}
|
||||
// Inclusive.
|
||||
@@ -1151,87 +1077,6 @@ ResolveCopyShaderIndex ResolveInfo::GetCopyShader(
|
||||
return shader;
|
||||
}
|
||||
|
||||
void GetPresentArea(uint32_t source_width, uint32_t source_height,
|
||||
uint32_t window_width, uint32_t window_height,
|
||||
int32_t& target_x_out, int32_t& target_y_out,
|
||||
uint32_t& target_width_out, uint32_t& target_height_out) {
|
||||
if (!cvars::present_rescale) {
|
||||
target_x_out = (int32_t(window_width) - int32_t(source_width)) / 2;
|
||||
target_y_out = (int32_t(window_height) - int32_t(source_height)) / 2;
|
||||
target_width_out = source_width;
|
||||
target_height_out = source_height;
|
||||
return;
|
||||
}
|
||||
// Prevent division by zero.
|
||||
if (!source_width || !source_height) {
|
||||
target_x_out = 0;
|
||||
target_y_out = 0;
|
||||
target_width_out = 0;
|
||||
target_height_out = 0;
|
||||
return;
|
||||
}
|
||||
if (uint64_t(window_width) * source_height >
|
||||
uint64_t(source_width) * window_height) {
|
||||
// The window is wider that the source - crop along Y, then letterbox or
|
||||
// stretch along X.
|
||||
uint32_t present_safe_area;
|
||||
if (cvars::present_safe_area_y > 0 && cvars::present_safe_area_y < 100) {
|
||||
present_safe_area = uint32_t(cvars::present_safe_area_y);
|
||||
} else {
|
||||
present_safe_area = 100;
|
||||
}
|
||||
uint32_t target_height =
|
||||
uint32_t(uint64_t(window_width) * source_height / source_width);
|
||||
bool letterbox = false;
|
||||
if (target_height * present_safe_area > window_height * 100) {
|
||||
// Don't crop out more than the safe area margin - letterbox or stretch.
|
||||
target_height = window_height * 100 / present_safe_area;
|
||||
letterbox = true;
|
||||
}
|
||||
if (letterbox && cvars::present_letterbox) {
|
||||
uint32_t target_width =
|
||||
uint32_t(uint64_t(source_width) * window_height * 100 /
|
||||
(source_height * present_safe_area));
|
||||
target_x_out = (int32_t(window_width) - int32_t(target_width)) / 2;
|
||||
target_width_out = target_width;
|
||||
} else {
|
||||
target_x_out = 0;
|
||||
target_width_out = window_width;
|
||||
}
|
||||
target_y_out = (int32_t(window_height) - int32_t(target_height)) / 2;
|
||||
target_height_out = target_height;
|
||||
} else {
|
||||
// The window is taller than the source - crop along X, then letterbox or
|
||||
// stretch along Y.
|
||||
uint32_t present_safe_area;
|
||||
if (cvars::present_safe_area_x > 0 && cvars::present_safe_area_x < 100) {
|
||||
present_safe_area = uint32_t(cvars::present_safe_area_x);
|
||||
} else {
|
||||
present_safe_area = 100;
|
||||
}
|
||||
uint32_t target_width =
|
||||
uint32_t(uint64_t(window_height) * source_width / source_height);
|
||||
bool letterbox = false;
|
||||
if (target_width * present_safe_area > window_width * 100) {
|
||||
// Don't crop out more than the safe area margin - letterbox or stretch.
|
||||
target_width = window_width * 100 / present_safe_area;
|
||||
letterbox = true;
|
||||
}
|
||||
if (letterbox && cvars::present_letterbox) {
|
||||
uint32_t target_height =
|
||||
uint32_t(uint64_t(source_height) * window_width * 100 /
|
||||
(source_width * present_safe_area));
|
||||
target_y_out = (int32_t(window_height) - int32_t(target_height)) / 2;
|
||||
target_height_out = target_height;
|
||||
} else {
|
||||
target_y_out = 0;
|
||||
target_height_out = window_height;
|
||||
}
|
||||
target_x_out = (int32_t(window_width) - int32_t(target_width)) / 2;
|
||||
target_width_out = target_width;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace draw_util
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
||||
Reference in New Issue
Block a user