Recreate NGX feature on render size mismatch
Fixes the black screen when the game renders at a different size than its DLSS feature (some games after a relaunch).
This commit is contained in:
1 parent
67c657bb90
commit
c4954dc3c4
2 files changed
+61
-3
No files matched your search
@@ -679,8 +679,13 @@ int main(int argc, char** argv)
|
|||||||
void* parameters = nullptr;
|
void* parameters = nullptr;
|
||||||
result = allocate(¶meters);
|
result = allocate(¶meters);
|
||||||
std::printf("AllocateParameters -> 0x%08x\n", result);
|
std::printf("AllocateParameters -> 0x%08x\n", result);
|
||||||
d4r_ngx_set_uint(parameters, "Width", inWidth);
|
// D4R_HARNESS_CREATE_SIZE=WxH creates the feature for another render size than the frames use, as
|
||||||
d4r_ngx_set_uint(parameters, "Height", inHeight);
|
// Streamline does for a frame or more after a quality change (PRAGMATA: 1280x720 feature, 854x480 frames).
|
||||||
|
unsigned int createWidth = inWidth, createHeight = inHeight;
|
||||||
|
if (const char* size = std::getenv("D4R_HARNESS_CREATE_SIZE"))
|
||||||
|
std::sscanf(size, "%ux%u", &createWidth, &createHeight);
|
||||||
|
d4r_ngx_set_uint(parameters, "Width", createWidth);
|
||||||
|
d4r_ngx_set_uint(parameters, "Height", createHeight);
|
||||||
d4r_ngx_set_uint(parameters, "OutWidth", outWidth);
|
d4r_ngx_set_uint(parameters, "OutWidth", outWidth);
|
||||||
d4r_ngx_set_uint(parameters, "OutHeight", outHeight);
|
d4r_ngx_set_uint(parameters, "OutHeight", outHeight);
|
||||||
// D4R_HARNESS_QUALITY selects NVSDK_NGX_PerfQuality_Value (default 2,
|
// D4R_HARNESS_QUALITY selects NVSDK_NGX_PerfQuality_Value (default 2,
|
||||||
|
|||||||
@@ -1676,6 +1676,8 @@ struct Feature
|
|||||||
void* cudaParams = nullptr;
|
void* cudaParams = nullptr;
|
||||||
CudaDevicePtr scratch = 0;
|
CudaDevicePtr scratch = 0;
|
||||||
unsigned int width = 0, height = 0, outWidth = 0, outHeight = 0;
|
unsigned int width = 0, height = 0, outWidth = 0, outHeight = 0;
|
||||||
|
unsigned int cudaWidth = 0, cudaHeight = 0; // render size the NGX feature was created with (worker only)
|
||||||
|
unsigned int refusedWidth = 0, refusedHeight = 0; // render size NGX would not create a feature for (worker only)
|
||||||
int quality = 0, flags = 0;
|
int quality = 0, flags = 0;
|
||||||
unsigned int preset = 0;
|
unsigned int preset = 0;
|
||||||
CudaEvent profileStart = nullptr, profileEnd = nullptr;
|
CudaEvent profileStart = nullptr, profileEnd = nullptr;
|
||||||
@@ -3894,6 +3896,53 @@ static void publish_vram(Feature* feature, uint32_t frame, const FrameParams& pa
|
|||||||
finish_publish(feature, target, frame, params, timing, start);
|
finish_publish(feature, target, frame, params, timing, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Worker. Streamline can create the feature at one quality's render size while the game still renders at
|
||||||
|
// another's (PRAGMATA starts with an Ultra Performance 854x480 frame on a Performance 1280x720 feature), and NGX
|
||||||
|
// rejects a subrect outside the feature's dynamic range on every frame until the game recreates it: a black
|
||||||
|
// screen. Recreate the NGX feature at the size actually rendered; the game's handle and output stay the same.
|
||||||
|
static bool recreate_for_render_size(Feature& feature, FrameParams& params, uint32_t frame)
|
||||||
|
{
|
||||||
|
if ((params.renderWidth == feature.cudaWidth && params.renderHeight == feature.cudaHeight) ||
|
||||||
|
(params.renderWidth == feature.refusedWidth && params.renderHeight == feature.refusedHeight))
|
||||||
|
return false;
|
||||||
|
logf("frame %u: NGX rejected render %ux%u on a %ux%u feature; recreating it at %ux%u", frame, params.renderWidth,
|
||||||
|
params.renderHeight, feature.cudaWidth, feature.cudaHeight, params.renderWidth, params.renderHeight);
|
||||||
|
// earlier frames' kernels may still be running on the old feature
|
||||||
|
synchronize_default_stream(feature);
|
||||||
|
if (feature.cudaHandle != nullptr)
|
||||||
|
g.ngx.releaseFeature(feature.cudaHandle);
|
||||||
|
feature.cudaHandle = nullptr;
|
||||||
|
void* p = feature.cudaParams;
|
||||||
|
d4r_ngx_set_uint(p, "Width", params.renderWidth);
|
||||||
|
d4r_ngx_set_uint(p, "Height", params.renderHeight);
|
||||||
|
NgxResult created = g.ngx.createFeature(NGX_FEATURE_SUPER_SAMPLING, p, &feature.cudaHandle);
|
||||||
|
unsigned int width = params.renderWidth, height = params.renderHeight;
|
||||||
|
if (created != NGX_SUCCESS)
|
||||||
|
{
|
||||||
|
logf("frame %u: recreating the NGX feature at %ux%u failed (0x%08x); restoring %ux%u", frame, width, height,
|
||||||
|
created, feature.cudaWidth, feature.cudaHeight);
|
||||||
|
feature.refusedWidth = width;
|
||||||
|
feature.refusedHeight = height;
|
||||||
|
width = feature.cudaWidth;
|
||||||
|
height = feature.cudaHeight;
|
||||||
|
d4r_ngx_set_uint(p, "Width", width);
|
||||||
|
d4r_ngx_set_uint(p, "Height", height);
|
||||||
|
feature.cudaHandle = nullptr;
|
||||||
|
created = g.ngx.createFeature(NGX_FEATURE_SUPER_SAMPLING, p, &feature.cudaHandle);
|
||||||
|
if (created != NGX_SUCCESS)
|
||||||
|
{
|
||||||
|
logf("frame %u: restoring the NGX feature failed (0x%08x)", frame, created);
|
||||||
|
feature.cudaHandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// a new feature has no history
|
||||||
|
feature.cudaWidth = width;
|
||||||
|
feature.cudaHeight = height;
|
||||||
|
params.reset = 1;
|
||||||
|
d4r_ngx_set_int(p, "Reset", 1);
|
||||||
|
return feature.cudaHandle != nullptr && width == params.renderWidth && height == params.renderHeight;
|
||||||
|
}
|
||||||
|
|
||||||
static void run_evaluation(Feature* feature, int slotIndex, uint32_t frame, FrameParams params, FrameTiming timing)
|
static void run_evaluation(Feature* feature, int slotIndex, uint32_t frame, FrameParams params, FrameTiming timing)
|
||||||
{
|
{
|
||||||
InputSlot& slot = feature->inputs[slotIndex];
|
InputSlot& slot = feature->inputs[slotIndex];
|
||||||
@@ -3993,7 +4042,9 @@ static void run_evaluation(Feature* feature, int slotIndex, uint32_t frame, Fram
|
|||||||
const int eventStartResult = timing.enabled && feature->profileEventsReady
|
const int eventStartResult = timing.enabled && feature->profileEventsReady
|
||||||
? g.cu.eventRecord(feature->profileStart, nullptr) : -1;
|
? g.cu.eventRecord(feature->profileStart, nullptr) : -1;
|
||||||
const auto evalStart = timing.enabled ? ProfileClock::now() : ProfileClock::time_point{};
|
const auto evalStart = timing.enabled ? ProfileClock::now() : ProfileClock::time_point{};
|
||||||
const NgxResult result = g.ngx.evaluateFeature(feature->cudaHandle, feature->cudaParams, nullptr);
|
NgxResult result = g.ngx.evaluateFeature(feature->cudaHandle, feature->cudaParams, nullptr);
|
||||||
|
if (result == NGX_FAIL_INVALID_PARAMETER && recreate_for_render_size(*feature, params, frame))
|
||||||
|
result = g.ngx.evaluateFeature(feature->cudaHandle, feature->cudaParams, nullptr);
|
||||||
if (feature->outputRedirected && g.cu.outputKernelNative != nullptr && g.cu.outputKernelNative() != 1)
|
if (feature->outputRedirected && g.cu.outputKernelNative != nullptr && g.cu.outputKernelNative() != 1)
|
||||||
{
|
{
|
||||||
// this frame's output kernel ignored the redirect: publish from the array as usual
|
// this frame's output kernel ignored the redirect: publish from the array as usual
|
||||||
@@ -4555,6 +4606,8 @@ D4R_EXPORT NgxResult NVSDK_NGX_D3D12_CreateFeature(ID3D12GraphicsCommandList*, u
|
|||||||
else
|
else
|
||||||
feature->scratch = 0;
|
feature->scratch = 0;
|
||||||
const NgxResult created = g.ngx.createFeature(NGX_FEATURE_SUPER_SAMPLING, p, &feature->cudaHandle);
|
const NgxResult created = g.ngx.createFeature(NGX_FEATURE_SUPER_SAMPLING, p, &feature->cudaHandle);
|
||||||
|
feature->cudaWidth = feature->width;
|
||||||
|
feature->cudaHeight = feature->height;
|
||||||
if (created == NGX_SUCCESS && env_uint("D4R_SHIM_BLOCKING_SYNC", 1) != 0 &&
|
if (created == NGX_SUCCESS && env_uint("D4R_SHIM_BLOCKING_SYNC", 1) != 0 &&
|
||||||
g.cu.eventCreate != nullptr && g.cu.eventRecord != nullptr &&
|
g.cu.eventCreate != nullptr && g.cu.eventRecord != nullptr &&
|
||||||
g.cu.eventSynchronize != nullptr && g.cu.eventQuery != nullptr && g.cu.eventDestroy != nullptr)
|
g.cu.eventSynchronize != nullptr && g.cu.eventQuery != nullptr && g.cu.eventDestroy != nullptr)
|
||||||
|
|||||||
Reference in new issue
Block a user