mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Fill the scene's last column or row from the one next to it after a jitter to the left or up, before DLSS or FSR reads the scene.
With FSR 4 or FSR 3.1 a light line flickered along the bottom and right edges of the picture. The jitter moves the scene's viewport by under half a pixel, which keeps every pixel centre inside it. Yet on an RX 7900 XT, a viewport moved up left the last row undrawn in every scene pass, and one moved left the last column. A frame dump showed the depth's last row at its clear value and the light target's last row holding the fog's colour, which the upscaler blended into the edge. NX2NAVI_DLAA_EDGE_FILL=0 turns the fill off for testing. Hyrule Field, 3416x1440, present screenshots: the outermost rows averaged 40 against 20 just inside without the fill, and within 1 of the inside with it. The same held with FSR 4.1 Native AA and Quality, FSR 3.1, SMAA and HDR. Jitter off, and no upscaler, gave no line either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
## Fixed
|
||||
|
||||
- **A flickering light line along the bottom and right edges of the picture with FSR 4, FSR 3.1 or DLSS.** To let the
|
||||
upscaler build a smoother picture, the scene is drawn moved by a fraction of a pixel, a little differently each frame.
|
||||
When it moved up or to the left, AMD's driver left the last row or column of the scene undrawn, the fog's colour stayed
|
||||
there, and the upscaler blended it into the edge. That row or column is now filled from the one next to it before the
|
||||
upscaler reads the scene.
|
||||
|
||||
## Changed
|
||||
|
||||
- **The Anti-aliasing setting works with FSR 4, FSR 3.1 and DLSS.** Choosing Game SMAA, Off, FXAA or SMAA (Ultra) with
|
||||
|
||||
@@ -44,7 +44,7 @@ static const char *const known[] = {
|
||||
"BIND_SKIP", "BIND_STATS", "BIND_UP", "BIND_X", "BIND_Y",
|
||||
"BIND_ZL", "BIND_ZR", "BLOCK_VIEWS_3D", "CACHE_DIE", "CLOTH_REALTIME", "COLOR_BRIGHTNESS", "COMPUTE_KEEP", "COLOR_CONTRAST", "COLOR_GAMMA",
|
||||
"COLOR_PRESET", "COLOR_SATURATION", "CONTACT_DEBUG", "CONTACT_SHADOWS", "CORE_DIAG", "CRIT", "CRIT_OUT",
|
||||
"DESC_TEMPLATE", "DEVICE_PROFILE", "DISCORD_APP_ID", "DISCORD_IMAGE", "DISCORD_RPC", "DLAA", "DLAA_CAM_KEEP", "DLSS_IDLE_FREE", "DLAA_JITTER", "DLAA_MV", "DLAA_MASKDEBUG", "DLAA_MVDEBUG", "DLAA_OBJMV", "DLAA_SURVEY", "DLAA_TARGET_KEEP", "DLAA_TIMES", "DLSS", "DLSS_CHAR_MASK", "DLSS_PRESET", "DLSS_REACTIVE", "DUMP", "DUMP_BUF", "DUMP_DIR",
|
||||
"DESC_TEMPLATE", "DEVICE_PROFILE", "DISCORD_APP_ID", "DISCORD_IMAGE", "DISCORD_RPC", "DLAA", "DLAA_CAM_KEEP", "DLSS_IDLE_FREE", "DLAA_EDGE_FILL", "DLAA_JITTER", "DLAA_MV", "DLAA_MASKDEBUG", "DLAA_MVDEBUG", "DLAA_OBJMV", "DLAA_SURVEY", "DLAA_TARGET_KEEP", "DLAA_TIMES", "DLSS", "DLSS_CHAR_MASK", "DLSS_PRESET", "DLSS_REACTIVE", "DUMP", "DUMP_BUF", "DUMP_DIR",
|
||||
"DUMP_LOG", "DUMP_RAW", "DUMP_SHADERS", "DUMP_FILE", "DS3", "LOG_CS_BINDS", "LOG_TEX_FLAGS", "LOG_MESH", "MESH", "POOL", "NATIVE_TENSOR", "LOG_RCOND", "LOG_RT_SIZES", "DUMP_WHITE", "DUMP_AFTER", "DUMP_MOVIE", "SUBMIT_FINISH", "ACQUIRE_WAIT", "CRASH_FILTER_GUARD", "CS_FALLBACK", "EXEFS", "FEEDBACK", "FIX_C0", "FIX_ZERO", "FLIGHT", "FLIGHT_AT", "FLIGHT_DIR", "FLIGHT_FRAMES", "GPU_TIMELINE",
|
||||
"FFX_PIPE_CACHE", "FLIGHT_SPIKE_MS", "FLIGHT_THUMBS", "FLIGHT_EVERY", "FLUSH_SPAN", "FLUSH_UPLOAD", "FOG_CULL", "FOLIAGE_SHADOW_CULL", "FOLIAGE_SHADOW_VRS", "FOV", "FOV_PATCH", "FG_HUDLESS_SHOW", "FG_MULT", "FPS60", "FPS_LIMIT", "FRAMEGEN", "FRAMEGEN_MULTIPLIER", "FREEZE_IDLE", "FREEZE_ASYNC", "FREEZE_BUDGET_US", "FREE_CORES",
|
||||
"FULLSCREEN", "FXAA", "GAME_ASPECT", "GAME_RES", "GPA", "GPA_EMPTY", "GPA_TWIN", "GPA_TWIN_MAX_KB", "MIRROR_CAPTURE_KB", "WB_SKIP_MB", "GPL", "GPL_DRAW_BUILD", "GPL_FEEDBACK", "PIPE_AHEAD", "PIPE_FAST_WORKERS", "PIPE_FRAME_WAIT_MS", "PIPE_LINK_DRAW_MS", "PIPE_SKIP_STEADY", "PROG_LEAD", "GPU", "GPU_INDEX", "GPU_PASSES", "GPU_NAME", "HDR",
|
||||
|
||||
@@ -1769,6 +1769,40 @@ static void release_kept(const struct Size *making, int all) {
|
||||
making->w, making->h, all ? "after a release" : "larger inputs");
|
||||
}
|
||||
|
||||
// The scene's last column and row after a jitter to the left or up. The jitter moves the scene's viewport by under half a
|
||||
// pixel (vk_dlaa_viewport), which keeps every pixel centre inside it, yet on an RX 7900 XT (AMD's Windows driver) the
|
||||
// draws of a viewport moved left left the last column out, and of one moved up the last row: the driver evidently limits
|
||||
// drawing to the whole pixels inside the viewport. In a frame dump (NX2NAVI_DUMP, Hyrule Field, 3416x1440, FSR 4 Native
|
||||
// AA) the depth's last row kept its clear value through every scene pass and the light target held the fog's colour
|
||||
// there, which the upscaler blended into a grey line along the bottom and right edges of the picture that flickered with
|
||||
// the jitter; with NX2NAVI_DLAA_JITTER=0, and without DLSS or FSR, there was no line. Before DLSS or FSR reads the scene,
|
||||
// such a column or row of the light target and of the depth (which the motion vectors are made from) is filled from the
|
||||
// one next to it. NX2NAVI_DLAA_EDGE_FILL=0 (test): not filled.
|
||||
static void edge_fill(VkCommandBuffer cb, const VkExecTarget *t, const VkExecTarget *z, float jx, float jy) {
|
||||
static int on = -1;
|
||||
if (on < 0) on = rt_knob("DLAA_EDGE_FILL", "1");
|
||||
uint32_t w = t->width, h = t->height;
|
||||
if (!on || w < 2 || h < 2 || (jx >= 0 && jy >= 0)) return;
|
||||
static int told;
|
||||
if (!told++) rt_log("dlaa: the scene's last column or row after a jitter to the left or up is filled from the one before it");
|
||||
// the column first, then the row over the whole width, so the corner comes from the filled column
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
if (pass ? jy >= 0 : jx >= 0) continue;
|
||||
VkOffset3D from = pass ? (VkOffset3D){0, (int32_t)h - 2, 0} : (VkOffset3D){(int32_t)w - 2, 0, 0};
|
||||
VkOffset3D to = pass ? (VkOffset3D){0, (int32_t)h - 1, 0} : (VkOffset3D){(int32_t)w - 1, 0, 0};
|
||||
VkExtent3D ext = pass ? (VkExtent3D){w, 1, 1} : (VkExtent3D){1, h, 1};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
const VkExecTarget *g = i ? z : t;
|
||||
if (!g->image || g->width != w || g->height != h) continue;
|
||||
VkImageAspectFlags a = i ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkImageCopy r = {.srcSubresource = {a, g->level, g->base_layer, 1}, .srcOffset = from,
|
||||
.dstSubresource = {a, g->level, g->base_layer, 1}, .dstOffset = to, .extent = ext};
|
||||
vkCmdCopyImage(cb, g->image, VK_IMAGE_LAYOUT_GENERAL, g->image, VK_IMAGE_LAYOUT_GENERAL, 1, &r);
|
||||
}
|
||||
full_barrier(cb);
|
||||
}
|
||||
}
|
||||
|
||||
// Set when the scene the upscaler runs on has another size than the last one; vk_dlaa_resized_take reads it.
|
||||
static volatile int32_t size_changed;
|
||||
|
||||
@@ -1799,6 +1833,7 @@ static void evaluate(VkExec *ex, const VkExecTarget *dst) {
|
||||
VkImageView zv = vk_exec_target_view(z->img, z->format, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_DEPTH_BIT, z->level,
|
||||
z->base_layer, 1, 0);
|
||||
float jx = D.jit_used ? D.ux : 0.0f, jy = D.jit_used ? D.uy : 0.0f;
|
||||
edge_fill(cb, t, z, jx, jy); // before the motion vectors read the depth
|
||||
static int no_mv = -1;
|
||||
if (no_mv < 0) no_mv = !rt_knob("DLAA_MV", "1"); // NX2NAVI_DLAA_MV=0: zero motion (test)
|
||||
int masked = 0, mv = no_mv ? 0 : mv_pass(ex, e, zv, jx, jy, char_bias(), &masked);
|
||||
|
||||
Reference in New Issue
Block a user