vulkan: run the engine on the game's device, without staging
Native Vulkan NGX callers now get d4r's own network for presets K, M and L, recorded straight into the caller's command buffer on the game's VkDevice with the same GameUpscaler/GameUpscalerM adapters the D3D12 path uses through vkd3d-proton. No CPU staging, CUDA evaluation or host wait. D4R_VULKAN_ENGINE=0 keeps the staging path, and anything the engine does not cover still goes there with a logged reason. - Inputs are sampled through the caller's views (SHADER_READ_ONLY_OPTIMAL, or GENERAL with D4R_VULKAN_INPUT_GENERAL=1); depth/stencil views get a depth-only view. The output must be an RGBA16F (or RGB10A2 with an RGB10 model) storage image the engine writes directly, since the resource contract gives STORAGE usage only. - Every recording ends with an event; engine objects of a released feature are destroyed once all recorded events fired, or at shutdown. - GetFeatureDeviceExtensionRequirements reports VK_KHR_cooperative_matrix and VK_EXT_shader_float8 where available. It applies d4r.ini first: games ask before NGX init, and engine_requested() would otherwise cache "off". - The engine accepts R16G16_SNORM motion vectors (Enshrouded). - Engine model loaders accept a native device (VulkanInterop::native). - Harness: D4R_HARNESS_ENGINE_DEVICE=1 (1.3 device with the engine's features), D4R_HARNESS_ALLOW_BLACK=1 (staging K's black reset frame). Harness vs the staging path (RX 9070, GE-Proton11-7, 640x360 -> 1280x720): K 99.6 % bit-identical, rest within one half-float ulp; M 52.7 dB, L 54.3 dB PSNR; dynamic, recreate and discard pass for K and M. In game, Enshrouded runs preset M on this path (docs/vulkan.md, SUPPORTED_GAMES.md). Signed-off-by: itchyfeetleech <[email protected]>
This commit is contained in:
1 parent
0e851b7f90
commit
60da7b9019
6 files changed
+508
-29
No files matched your search
@@ -28,7 +28,7 @@ using Shutdown = Result (*)();
|
||||
|
||||
#define VK_FUNCTIONS(X) \
|
||||
X(CreateInstance) X(EnumeratePhysicalDevices) X(GetPhysicalDeviceProperties) X(EnumerateDeviceExtensionProperties) \
|
||||
X(GetPhysicalDeviceQueueFamilyProperties) X(GetPhysicalDeviceMemoryProperties) X(CreateDevice) \
|
||||
X(GetPhysicalDeviceQueueFamilyProperties) X(GetPhysicalDeviceMemoryProperties) X(GetPhysicalDeviceFeatures2) X(CreateDevice) \
|
||||
X(GetDeviceProcAddr) X(GetDeviceQueue) X(CreateCommandPool) X(AllocateCommandBuffers) \
|
||||
X(BeginCommandBuffer) X(EndCommandBuffer) X(ResetCommandPool) X(QueueSubmit) X(QueueWaitIdle) X(CreateFence) X(WaitForFences) X(ResetFences) X(DestroyFence) \
|
||||
X(CreateImage) X(GetImageMemoryRequirements) X(AllocateMemory) X(BindImageMemory) X(CreateImageView) \
|
||||
@@ -102,7 +102,10 @@ int main(int argc, char** argv)
|
||||
#define LOAD(name) vk##name = reinterpret_cast<PFN_vk##name>(ip(VK_NULL_HANDLE, "vk" #name));
|
||||
LOAD(CreateInstance)
|
||||
#undef LOAD
|
||||
VkApplicationInfo app = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; app.apiVersion = VK_API_VERSION_1_1;
|
||||
// D4R_HARNESS_ENGINE_DEVICE=1: a Vulkan 1.3 device with every supported 1.1-1.3 feature plus cooperative matrix
|
||||
// and shader float8, as d4r's engine (and a layer in a game) needs.
|
||||
const bool engineDevice = std::getenv("D4R_HARNESS_ENGINE_DEVICE") != nullptr;
|
||||
VkApplicationInfo app = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; app.apiVersion = engineDevice ? VK_API_VERSION_1_3 : VK_API_VERSION_1_1;
|
||||
VkInstanceCreateInfo ci = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; ci.pApplicationInfo = &app;
|
||||
VkInstance instance;
|
||||
check(vkCreateInstance(&ci,nullptr,&instance),"instance");
|
||||
@@ -142,6 +145,28 @@ int main(int argc, char** argv)
|
||||
di.enabledExtensionCount=1; di.ppEnabledExtensionNames=&externalExtension;
|
||||
std::puts("enabling external-memory VRAM interop");
|
||||
}
|
||||
VkPhysicalDeviceShaderFloat8FeaturesEXT f8 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT8_FEATURES_EXT};
|
||||
VkPhysicalDeviceCooperativeMatrixFeaturesKHR cm = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, &f8};
|
||||
VkPhysicalDeviceVulkan13Features v13 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, &cm};
|
||||
VkPhysicalDeviceVulkan12Features v12 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, &v13};
|
||||
VkPhysicalDeviceVulkan11Features v11 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, &v12};
|
||||
VkPhysicalDeviceFeatures2 f2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &v11};
|
||||
std::vector<const char*> engineExtensions;
|
||||
if (engineDevice) {
|
||||
vkGetPhysicalDeviceFeatures2(physical,&f2);
|
||||
check(vkEnumerateDeviceExtensionProperties(physical,nullptr,&count,nullptr),"extensions");
|
||||
std::vector<VkExtensionProperties> extensions(count);
|
||||
check(vkEnumerateDeviceExtensionProperties(physical,nullptr,&count,extensions.data()),"extensions");
|
||||
bool float8 = false;
|
||||
for (const auto& e : extensions) float8 |= std::strcmp(e.extensionName,"VK_EXT_shader_float8")==0;
|
||||
if (!float8) { f8.shaderFloat8 = f8.shaderFloat8CooperativeMatrix = VK_FALSE; cm.pNext = nullptr; }
|
||||
if (cm.cooperativeMatrix) engineExtensions.push_back("VK_KHR_cooperative_matrix"); else v13.pNext = nullptr;
|
||||
if (float8) engineExtensions.push_back("VK_EXT_shader_float8");
|
||||
for (uint32_t i = 0; i < di.enabledExtensionCount; ++i) engineExtensions.push_back(di.ppEnabledExtensionNames[i]);
|
||||
di.pNext = &f2; di.enabledExtensionCount = static_cast<uint32_t>(engineExtensions.size());
|
||||
di.ppEnabledExtensionNames = engineExtensions.data();
|
||||
std::printf("engine device: cooperative matrix %u, float8 %u\n", cm.cooperativeMatrix, f8.shaderFloat8);
|
||||
}
|
||||
check(vkCreateDevice(physical,&di,nullptr,&device),"device");
|
||||
auto dp = vkGetDeviceProcAddr;
|
||||
#define LOAD(name) vk##name = reinterpret_cast<PFN_vk##name>(dp(device, "vk" #name));
|
||||
@@ -247,7 +272,8 @@ int main(int argc, char** argv)
|
||||
unsigned nonzero=0, nonfinite=0;
|
||||
for (unsigned j=0;j<OW*OH*4;++j) { nonzero += (values[j]&0x7fff)!=0; nonfinite += (values[j]&0x7c00)==0x7c00; }
|
||||
std::printf("frame %u: nonzero=%u nonfinite=%u center=%04x,%04x,%04x,%04x\n",n,nonzero,nonfinite,values[((OH/2)*OW+OW/2)*4],values[((OH/2)*OW+OW/2)*4+1],values[((OH/2)*OW+OW/2)*4+2],values[((OH/2)*OW+OW/2)*4+3]);
|
||||
if (!nonzero || nonfinite) return 1;
|
||||
// D4R_HARNESS_ALLOW_BLACK=1: a black frame is reported but not fatal (NGX's K starts black on the reset frame here).
|
||||
if (nonfinite || (!nonzero && !std::getenv("D4R_HARNESS_ALLOW_BLACK"))) return 1;
|
||||
if (n+1==frames) { FILE* out=std::fopen(argv[2],"wb"); if (!out) return 1; const auto written=std::fwrite(data,1,OW*OH*8,out); std::fclose(out); if (written!=OW*OH*8) return 1; }
|
||||
vkUnmapMemory(device,readMemory);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user