Merge 9f9843ef62
into 149cf26e12
This commit is contained in:
commit
291127cf9b
|
@ -41,12 +41,20 @@ if(CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR CMAKE_EXE_LINKER_FLAGS STREQUAL "/
|
|||
set(FSR2_PLATFORM_NAME x64)
|
||||
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "Win32" OR CMAKE_EXE_LINKER_FLAGS STREQUAL "/machine:X86")
|
||||
set(FSR2_PLATFORM_NAME x86)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR)
|
||||
set(FSR2_PLATFORM_NAME ${CMAKE_SYSTEM_PROCESSOR})
|
||||
|
||||
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT MSVC))
|
||||
add_compile_definitions(FFX_GCC) # Should work with gcc and others
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported target platform - only supporting x64 and Win32 currently")
|
||||
endif()
|
||||
|
||||
# Embed PDBs in the debug versions of the libs
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Z7")
|
||||
if (MSVC)
|
||||
# Embed PDBs in the debug versions of the libs
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Z7")
|
||||
endif()
|
||||
|
||||
# Write both debug and release versions of the static libs to the /lib folder as they are uniquely named
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_HOME_DIRECTORY}/bin/ffx_fsr2_api/)
|
||||
|
@ -63,8 +71,13 @@ if(FSR2_VS_VERSION STREQUAL 2015)
|
|||
set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION "10.0.18362.0")
|
||||
endif()
|
||||
|
||||
set(FFX_SC_EXECUTABLE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../tools/sc/FidelityFX_SC.exe)
|
||||
if (WIN32)
|
||||
set(FFX_SC_EXECUTABLE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../tools/sc/FidelityFX_SC.exe)
|
||||
else()
|
||||
set(FFX_SC_EXECUTABLE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../tools/sc/FidelityFX_SC.sh)
|
||||
endif()
|
||||
|
||||
set(FFX_SC_BASE_ARGS
|
||||
-reflection -deps=gcc -DFFX_GPU=1
|
||||
|
@ -75,16 +88,30 @@ set(FFX_SC_BASE_ARGS
|
|||
-DFFX_FSR2_OPTION_POSTPROCESSLOCKSTATUS_SAMPLERS_USE_DATA_HALF=0
|
||||
# Upsample uses lanczos approximation
|
||||
-DFFX_FSR2_OPTION_UPSAMPLE_USE_LANCZOS_TYPE=2
|
||||
)
|
||||
)
|
||||
|
||||
set(FFX_SC_PERMUTATION_ARGS
|
||||
# Reproject can use either reference lanczos or LUT
|
||||
-DFFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE={0,1}
|
||||
-DFFX_FSR2_OPTION_HDR_COLOR_INPUT={0,1}
|
||||
-DFFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS={0,1}
|
||||
-DFFX_FSR2_OPTION_JITTERED_MOTION_VECTORS={0,1}
|
||||
-DFFX_FSR2_OPTION_INVERTED_DEPTH={0,1}
|
||||
-DFFX_FSR2_OPTION_APPLY_SHARPENING={0,1})
|
||||
if (WIN32)
|
||||
set(FFX_SC_PERMUTATION_ARGS
|
||||
# Reproject can use either reference lanczos or LUT
|
||||
-DFFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE={0,1}
|
||||
-DFFX_FSR2_OPTION_HDR_COLOR_INPUT={0,1}
|
||||
-DFFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS={0,1}
|
||||
-DFFX_FSR2_OPTION_JITTERED_MOTION_VECTORS={0,1}
|
||||
-DFFX_FSR2_OPTION_INVERTED_DEPTH={0,1}
|
||||
-DFFX_FSR2_OPTION_APPLY_SHARPENING={0,1}
|
||||
)
|
||||
else()
|
||||
# Fix bash curly braces replacement
|
||||
set(FFX_SC_PERMUTATION_ARGS
|
||||
# Reproject can use either reference lanczos or LUT
|
||||
'-DFFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE={0,1}'
|
||||
'-DFFX_FSR2_OPTION_HDR_COLOR_INPUT={0,1}'
|
||||
'-DFFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS={0,1}'
|
||||
'-DFFX_FSR2_OPTION_JITTERED_MOTION_VECTORS={0,1}'
|
||||
'-DFFX_FSR2_OPTION_INVERTED_DEPTH={0,1}'
|
||||
'-DFFX_FSR2_OPTION_APPLY_SHARPENING={0,1}'
|
||||
)
|
||||
endif()
|
||||
|
||||
file(GLOB SOURCES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
|
||||
|
@ -96,14 +123,20 @@ else()
|
|||
add_library(ffx_fsr2_api_${FSR2_PLATFORM_NAME} STATIC ${SOURCES})
|
||||
endif()
|
||||
|
||||
set(FFX_FSR2_API ffx_fsr2_api_${FSR2_PLATFORM_NAME} PARENT_SCOPE)
|
||||
|
||||
# graphics api backends
|
||||
if(FFX_FSR2_API_DX12)
|
||||
message("Will build FSR2 library: DX12 backend")
|
||||
add_subdirectory(dx12)
|
||||
|
||||
set(FFX_FSR2_API_DX12 ffx_fsr2_api_dx12_${FSR2_PLATFORM_NAME} PARENT_SCOPE)
|
||||
endif()
|
||||
if(FFX_FSR2_API_VK)
|
||||
message("Will build FSR2 library: Vulkan backend")
|
||||
add_subdirectory(vk)
|
||||
|
||||
set(FFX_FSR2_API_VK ffx_fsr2_api_vk_${FSR2_PLATFORM_NAME} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# api
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <algorithm> // for max used inside SPD CPU code.
|
||||
#include <cmath> // for fabs, abs, sinf, sqrt, etc.
|
||||
#include <string.h> // for memset
|
||||
#include <wchar.h> // for wcscmp, wcscpy
|
||||
#include <cfloat> // for FLT_EPSILON
|
||||
#include "ffx_fsr2.h"
|
||||
#define FFX_CPU
|
||||
|
@ -36,6 +37,10 @@
|
|||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
|
||||
#ifndef _countof
|
||||
#define _countof(array) (sizeof(array) / sizeof(array[0]))
|
||||
#endif
|
||||
|
||||
// max queued frames for descriptor management
|
||||
static const uint32_t FSR2_MAX_QUEUED_FRAMES = 16;
|
||||
|
||||
|
@ -94,6 +99,9 @@ static const ResourceBinding uavResourceBindingTable[] =
|
|||
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_REACTIVE_MASKS, L"rw_dilated_reactive_masks"},
|
||||
{FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE, L"rw_auto_exposure"},
|
||||
{FFX_FSR2_RESOURCE_IDENTIFIER_SPD_ATOMIC_COUNT, L"rw_spd_global_atomic"},
|
||||
#if defined(FFX_INTERNAL)
|
||||
{FFX_FSR2_RESOURCE_IDENTIFIER_DEBUG_OUTPUT, L"rw_debug_out"},
|
||||
#endif
|
||||
{FFX_FSR2_RESOURCE_IDENTIFIER_NEW_LOCKS, L"rw_new_locks"},
|
||||
{FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_INPUT_LUMA, L"rw_lock_input_luma"},
|
||||
{FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE, L"rw_output_autoreactive"},
|
||||
|
@ -182,7 +190,7 @@ FfxConstantBuffer globalFsr2ConstantBuffers[4] = {
|
|||
// Lanczos
|
||||
static float lanczos2(float value)
|
||||
{
|
||||
return abs(value) < FFX_EPSILON ? 1.f : (sinf(FFX_PI * value) / (FFX_PI * value)) * (sinf(0.5f * FFX_PI * value) / (0.5f * FFX_PI * value));
|
||||
return std::abs(value) < FFX_EPSILON ? 1.f : (sinf(FFX_PI * value) / (FFX_PI * value)) * (sinf(0.5f * FFX_PI * value) / (0.5f * FFX_PI * value));
|
||||
}
|
||||
|
||||
// Calculate halton number for index and base.
|
||||
|
@ -377,7 +385,7 @@ static FfxErrorCode patchResourceBindings(FfxPipelineState* inoutPipeline)
|
|||
inoutPipeline->cbResourceBindings[cbIndex].resourceIdentifier = cbResourceBindingTable[mapIndex].index;
|
||||
}
|
||||
|
||||
return FFX_OK;
|
||||
return FFX_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -415,7 +423,7 @@ static FfxErrorCode createPipelineStates(FfxFsr2Context_Private* context)
|
|||
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_LOCK, &pipelineDescription, &context->pipelineLock));
|
||||
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_ACCUMULATE, &pipelineDescription, &context->pipelineAccumulate));
|
||||
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_ACCUMULATE_SHARPEN, &pipelineDescription, &context->pipelineAccumulateSharpen));
|
||||
|
||||
|
||||
// for each pipeline: re-route/fix-up IDs based on names
|
||||
patchResourceBindings(&context->pipelineDepthClip);
|
||||
patchResourceBindings(&context->pipelineReconstructPreviousDepth);
|
||||
|
@ -720,13 +728,13 @@ static void scheduleDispatch(FfxFsr2Context_Private* context, const FfxFsr2Dispa
|
|||
const uint32_t currentResourceId = pipeline->srvResourceBindings[currentShaderResourceViewIndex].resourceIdentifier;
|
||||
const FfxResourceInternal currentResource = context->srvResources[currentResourceId];
|
||||
jobDescriptor.srvs[currentShaderResourceViewIndex] = currentResource;
|
||||
wcscpy_s(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
|
||||
wcscpy(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
|
||||
}
|
||||
|
||||
for (uint32_t currentUnorderedAccessViewIndex = 0; currentUnorderedAccessViewIndex < pipeline->uavCount; ++currentUnorderedAccessViewIndex) {
|
||||
|
||||
const uint32_t currentResourceId = pipeline->uavResourceBindings[currentUnorderedAccessViewIndex].resourceIdentifier;
|
||||
wcscpy_s(jobDescriptor.uavNames[currentUnorderedAccessViewIndex], pipeline->uavResourceBindings[currentUnorderedAccessViewIndex].name);
|
||||
wcscpy(jobDescriptor.uavNames[currentUnorderedAccessViewIndex], pipeline->uavResourceBindings[currentUnorderedAccessViewIndex].name);
|
||||
|
||||
if (currentResourceId >= FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0 && currentResourceId <= FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_12)
|
||||
{
|
||||
|
@ -741,14 +749,14 @@ static void scheduleDispatch(FfxFsr2Context_Private* context, const FfxFsr2Dispa
|
|||
jobDescriptor.uavMip[currentUnorderedAccessViewIndex] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jobDescriptor.dimensions[0] = dispatchX;
|
||||
jobDescriptor.dimensions[1] = dispatchY;
|
||||
jobDescriptor.dimensions[2] = 1;
|
||||
jobDescriptor.pipeline = *pipeline;
|
||||
|
||||
for (uint32_t currentRootConstantIndex = 0; currentRootConstantIndex < pipeline->constCount; ++currentRootConstantIndex) {
|
||||
wcscpy_s( jobDescriptor.cbNames[currentRootConstantIndex], pipeline->cbResourceBindings[currentRootConstantIndex].name);
|
||||
wcscpy( jobDescriptor.cbNames[currentRootConstantIndex], pipeline->cbResourceBindings[currentRootConstantIndex].name);
|
||||
jobDescriptor.cbs[currentRootConstantIndex] = globalFsr2ConstantBuffers[pipeline->cbResourceBindings[currentRootConstantIndex].resourceIdentifier];
|
||||
jobDescriptor.cbSlotIndex[currentRootConstantIndex] = pipeline->cbResourceBindings[currentRootConstantIndex].slotIndex;
|
||||
}
|
||||
|
@ -1257,9 +1265,9 @@ FfxErrorCode ffxFsr2ContextGenerateReactiveMask(FfxFsr2Context* context, const F
|
|||
|
||||
jobDescriptor.uavs[0] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE];
|
||||
|
||||
wcscpy_s(jobDescriptor.srvNames[0], pipeline->srvResourceBindings[0].name);
|
||||
wcscpy_s(jobDescriptor.srvNames[1], pipeline->srvResourceBindings[1].name);
|
||||
wcscpy_s(jobDescriptor.uavNames[0], pipeline->uavResourceBindings[0].name);
|
||||
wcscpy(jobDescriptor.srvNames[0], pipeline->srvResourceBindings[0].name);
|
||||
wcscpy(jobDescriptor.srvNames[1], pipeline->srvResourceBindings[1].name);
|
||||
wcscpy(jobDescriptor.uavNames[0], pipeline->uavResourceBindings[0].name);
|
||||
|
||||
jobDescriptor.dimensions[0] = dispatchSrcX;
|
||||
jobDescriptor.dimensions[1] = dispatchSrcY;
|
||||
|
@ -1271,7 +1279,7 @@ FfxErrorCode ffxFsr2ContextGenerateReactiveMask(FfxFsr2Context* context, const F
|
|||
const uint32_t currentResourceId = pipeline->srvResourceBindings[currentShaderResourceViewIndex].resourceIdentifier;
|
||||
const FfxResourceInternal currentResource = contextPrivate->srvResources[currentResourceId];
|
||||
jobDescriptor.srvs[currentShaderResourceViewIndex] = currentResource;
|
||||
wcscpy_s(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
|
||||
wcscpy(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
|
||||
}
|
||||
|
||||
Fsr2GenerateReactiveConstants constants = {};
|
||||
|
@ -1282,7 +1290,7 @@ FfxErrorCode ffxFsr2ContextGenerateReactiveMask(FfxFsr2Context* context, const F
|
|||
|
||||
jobDescriptor.cbs[0].uint32Size = sizeof(constants);
|
||||
memcpy(&jobDescriptor.cbs[0].data, &constants, sizeof(constants));
|
||||
wcscpy_s(jobDescriptor.cbNames[0], pipeline->cbResourceBindings[0].name);
|
||||
wcscpy(jobDescriptor.cbNames[0], pipeline->cbResourceBindings[0].name);
|
||||
|
||||
FfxGpuJobDescription dispatchJob = { FFX_GPU_JOB_COMPUTE };
|
||||
dispatchJob.computeJobDescriptor = jobDescriptor;
|
||||
|
@ -1323,10 +1331,10 @@ static FfxErrorCode generateReactiveMaskInternal(FfxFsr2Context_Private* context
|
|||
jobDescriptor.uavs[2] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR];
|
||||
jobDescriptor.uavs[3] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR];
|
||||
|
||||
wcscpy_s(jobDescriptor.uavNames[0], pipeline->uavResourceBindings[0].name);
|
||||
wcscpy_s(jobDescriptor.uavNames[1], pipeline->uavResourceBindings[1].name);
|
||||
wcscpy_s(jobDescriptor.uavNames[2], pipeline->uavResourceBindings[2].name);
|
||||
wcscpy_s(jobDescriptor.uavNames[3], pipeline->uavResourceBindings[3].name);
|
||||
wcscpy(jobDescriptor.uavNames[0], pipeline->uavResourceBindings[0].name);
|
||||
wcscpy(jobDescriptor.uavNames[1], pipeline->uavResourceBindings[1].name);
|
||||
wcscpy(jobDescriptor.uavNames[2], pipeline->uavResourceBindings[2].name);
|
||||
wcscpy(jobDescriptor.uavNames[3], pipeline->uavResourceBindings[3].name);
|
||||
|
||||
jobDescriptor.dimensions[0] = dispatchSrcX;
|
||||
jobDescriptor.dimensions[1] = dispatchSrcY;
|
||||
|
@ -1338,11 +1346,11 @@ static FfxErrorCode generateReactiveMaskInternal(FfxFsr2Context_Private* context
|
|||
const uint32_t currentResourceId = pipeline->srvResourceBindings[currentShaderResourceViewIndex].resourceIdentifier;
|
||||
const FfxResourceInternal currentResource = contextPrivate->srvResources[currentResourceId];
|
||||
jobDescriptor.srvs[currentShaderResourceViewIndex] = currentResource;
|
||||
wcscpy_s(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
|
||||
wcscpy(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
|
||||
}
|
||||
|
||||
for (uint32_t currentRootConstantIndex = 0; currentRootConstantIndex < pipeline->constCount; ++currentRootConstantIndex) {
|
||||
wcscpy_s(jobDescriptor.cbNames[currentRootConstantIndex], pipeline->cbResourceBindings[currentRootConstantIndex].name);
|
||||
wcscpy(jobDescriptor.cbNames[currentRootConstantIndex], pipeline->cbResourceBindings[currentRootConstantIndex].name);
|
||||
jobDescriptor.cbs[currentRootConstantIndex] = globalFsr2ConstantBuffers[pipeline->cbResourceBindings[currentRootConstantIndex].resourceIdentifier];
|
||||
jobDescriptor.cbSlotIndex[currentRootConstantIndex] = pipeline->cbResourceBindings[currentRootConstantIndex].slotIndex;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined (FFX_GCC)
|
||||
/// FidelityFX exported functions
|
||||
|
|
|
@ -80,8 +80,13 @@ foreach(PASS_SHADER ${PASS_SHADERS})
|
|||
# skip 16-bit permutations for the compute luminance pyramid pass
|
||||
set(FFX_SC_ARGS ${FFX_SC_BASE_ARGS} ${FFX_SC_VK_BASE_ARGS} ${FFX_SC_PERMUTATION_ARGS} -DFFX_HALF=0)
|
||||
else()
|
||||
set(FFX_SC_ARGS ${FFX_SC_BASE_ARGS} ${FFX_SC_VK_BASE_ARGS} ${FFX_SC_PERMUTATION_ARGS} -DFFX_HALF={0,1})
|
||||
endif()
|
||||
if (WIN32)
|
||||
set(FFX_SC_ARGS ${FFX_SC_BASE_ARGS} ${FFX_SC_VK_BASE_ARGS} ${FFX_SC_PERMUTATION_ARGS} -DFFX_HALF={0,1})
|
||||
else()
|
||||
# Fix bash curly braces replacement
|
||||
set(FFX_SC_ARGS ${FFX_SC_BASE_ARGS} ${FFX_SC_VK_BASE_ARGS} ${FFX_SC_PERMUTATION_ARGS} '-DFFX_HALF={0,1}')
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_DEPFILE)
|
||||
add_custom_command(
|
||||
|
@ -107,4 +112,4 @@ add_custom_target(shader_permutations_vk DEPENDS ${PERMUTATION_OUTPUTS})
|
|||
add_dependencies(${FFX_SC_DEPENDENT_TARGET} shader_permutations_vk)
|
||||
|
||||
source_group("source" FILES ${VK})
|
||||
source_group("shaders" FILES ${SHADERS})
|
||||
source_group("shaders" FILES ${SHADERS})
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
|
||||
// prototypes for functions in the interface
|
||||
FfxErrorCode GetDeviceCapabilitiesVK(FfxFsr2Interface* backendInterface, FfxDeviceCapabilities* deviceCapabilities, FfxDevice device);
|
||||
|
@ -573,7 +574,7 @@ FfxResource ffxGetTextureResourceVK(FfxFsr2Context* context, VkImage imgVk, VkIm
|
|||
|
||||
#ifdef _DEBUG
|
||||
if (name) {
|
||||
wcscpy_s(resource.name, name);
|
||||
wcscpy(resource.name, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -597,7 +598,7 @@ FfxResource ffxGetBufferResourceVK(FfxFsr2Context* context, VkBuffer bufVk, uint
|
|||
|
||||
#ifdef _DEBUG
|
||||
if (name) {
|
||||
wcscpy_s(resource.name, name);
|
||||
wcscpy(resource.name, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1331,17 +1332,17 @@ FfxErrorCode CreatePipelineVK(FfxFsr2Interface* backendInterface, FfxFsr2Pass pa
|
|||
for (uint32_t srvIndex = 0; srvIndex < outPipeline->srvCount; ++srvIndex)
|
||||
{
|
||||
outPipeline->srvResourceBindings[srvIndex].slotIndex = shaderBlob.boundSampledImageBindings[srvIndex];
|
||||
wcscpy_s(outPipeline->srvResourceBindings[srvIndex].name, converter.from_bytes(shaderBlob.boundSampledImageNames[srvIndex]).c_str());
|
||||
wcscpy(outPipeline->srvResourceBindings[srvIndex].name, converter.from_bytes(shaderBlob.boundSampledImageNames[srvIndex]).c_str());
|
||||
}
|
||||
for (uint32_t uavIndex = 0; uavIndex < outPipeline->uavCount; ++uavIndex)
|
||||
{
|
||||
outPipeline->uavResourceBindings[uavIndex].slotIndex = shaderBlob.boundStorageImageBindings[uavIndex];
|
||||
wcscpy_s(outPipeline->uavResourceBindings[uavIndex].name, converter.from_bytes(shaderBlob.boundStorageImageNames[uavIndex]).c_str());
|
||||
wcscpy(outPipeline->uavResourceBindings[uavIndex].name, converter.from_bytes(shaderBlob.boundStorageImageNames[uavIndex]).c_str());
|
||||
}
|
||||
for (uint32_t cbIndex = 0; cbIndex < outPipeline->constCount; ++cbIndex)
|
||||
{
|
||||
outPipeline->cbResourceBindings[cbIndex].slotIndex = shaderBlob.boundUniformBufferBindings[cbIndex];
|
||||
wcscpy_s(outPipeline->cbResourceBindings[cbIndex].name, converter.from_bytes(shaderBlob.boundUniformBufferNames[cbIndex]).c_str());
|
||||
wcscpy(outPipeline->cbResourceBindings[cbIndex].name, converter.from_bytes(shaderBlob.boundUniformBufferNames[cbIndex]).c_str());
|
||||
}
|
||||
|
||||
// create descriptor set layout
|
||||
|
|
291
tools/sc/FidelityFX_SC.py
Executable file
291
tools/sc/FidelityFX_SC.py
Executable file
|
@ -0,0 +1,291 @@
|
|||
#!/bin/python
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import mmap
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
def hash_file(path):
|
||||
algorithm = hashlib.md5()
|
||||
with open(path, 'rb') as file:
|
||||
with mmap.mmap(file.fileno(), 0, prot=mmap.PROT_READ) as memory:
|
||||
algorithm.update(memory)
|
||||
return algorithm.hexdigest()
|
||||
|
||||
|
||||
def append_resources(code, name, data, key, resource_name):
|
||||
if not key in data:
|
||||
return
|
||||
|
||||
for res in data[key]:
|
||||
if res['name'][-2:] == '_t':
|
||||
res['name'] = res['name'][:-2]
|
||||
|
||||
data[key].sort(key=lambda res: res['binding'])
|
||||
|
||||
code.append('static const char* g_{0}_{1}ResourceNames[] ='.format(name, resource_name))
|
||||
code.append('{ ' + ', '.join(['"{0}"'.format(res['name']) for res in data[key]]) + ', };')
|
||||
code.append('static const uint32_t g_{0}_{1}ResourceBindings[] ='.format(name, resource_name))
|
||||
code.append('{ ' + ', '.join([str(res['binding']) for res in data[key]]) + ', };')
|
||||
code.append('static const uint32_t g_{0}_{1}ResourceCounts[] ='.format(name, resource_name))
|
||||
code.append('{ ' + ', '.join(['1' for res in data[key]]) + ', };')
|
||||
code.append('static const uint32_t g_{0}_{1}ResourceSets[] ='.format(name, resource_name))
|
||||
code.append('{ ' + ', '.join([str(res['set']) for res in data[key]]) + ', };')
|
||||
code.append('')
|
||||
|
||||
|
||||
def process(file, name, args, output, optimization, reflection):
|
||||
spirv_path = os.path.join(output, name + '.spv')
|
||||
subprocess.run(['glslangValidator', '-V', *args, '-o', spirv_path, file])
|
||||
|
||||
if optimization:
|
||||
optimized_spirv_path = spirv_path + '_opt'
|
||||
subprocess.run(['spirv-opt', '-Os', spirv_path, '-o', optimized_spirv_path])
|
||||
os.rename(optimized_spirv_path, spirv_path)
|
||||
|
||||
spirv_hash = hash_file(spirv_path)
|
||||
name = '{0}_{1}'.format(name, str(spirv_hash))
|
||||
hash_path = os.path.join(output, name + '.spv')
|
||||
|
||||
if os.path.exists(hash_path):
|
||||
os.remove(spirv_path)
|
||||
return name, dict()
|
||||
else:
|
||||
os.rename(spirv_path, hash_path)
|
||||
spirv_path = hash_path
|
||||
|
||||
spirv = list()
|
||||
with open(spirv_path, 'rb') as spirv_file:
|
||||
spirv = list(spirv_file.read())
|
||||
|
||||
data = dict()
|
||||
if reflection:
|
||||
json_path = os.path.join(output, name + '.json')
|
||||
subprocess.run(['spirv-cross', '-V', spirv_path, '--reflect', '--output', json_path])
|
||||
|
||||
with open(json_path) as json_file:
|
||||
data = json.load(json_file)
|
||||
|
||||
os.remove(json_path)
|
||||
|
||||
code = ['// {0}.h.'.format(name), '// Auto generated by FidelityFX-SC.py.', '']
|
||||
|
||||
append_resources(code, name, data, 'separate_samplers', 'Sampler')
|
||||
append_resources(code, name, data, 'combined_samplers', 'CombinedSampler')
|
||||
append_resources(code, name, data, 'separate_images', 'SampledImage')
|
||||
append_resources(code, name, data, 'images', 'StorageImage')
|
||||
append_resources(code, name, data, 'uniform_texel_buffers', 'UniformTexelBuffer')
|
||||
append_resources(code, name, data, 'storage_texel_buffers', 'StorageTexelBuffer')
|
||||
append_resources(code, name, data, 'ubos', 'UniformBuffer')
|
||||
append_resources(code, name, data, 'sbos', 'StorageBuffer')
|
||||
append_resources(code, name, data, 'inputs', 'InputAttachment')
|
||||
append_resources(code, name, data, 'acceleration_structures', 'AccelerationStructure')
|
||||
|
||||
code.append('static const uint32_t g_{0}_size = {1};'.format(name, len(spirv)))
|
||||
code.append('')
|
||||
code.append('static const unsigned char g_{0}_data[] = '.format(name) + '{')
|
||||
|
||||
for i in range(0, len(spirv), 16):
|
||||
line = ','.join(map('0x{0:02x}'.format, spirv[i:i + 16]))
|
||||
if i + 16 < len(spirv):
|
||||
line = line + ','
|
||||
code.append(line)
|
||||
|
||||
code.append('};')
|
||||
code_path = os.path.join(output, name + '.h')
|
||||
with open(code_path, 'w') as code_file:
|
||||
code_file.write('\n'.join(code))
|
||||
|
||||
return name, data
|
||||
|
||||
|
||||
def append_resources_info(code, resources_name, resource_name):
|
||||
code.append('\tconst uint32_t num{0}Resources;'.format(resources_name))
|
||||
code.append('\tconst char** {0}ResourceNames;'.format(resource_name))
|
||||
code.append('\tconst uint32_t* {0}ResourceBindings;'.format(resource_name))
|
||||
code.append('\tconst uint32_t* {0}ResourceCounts;'.format(resource_name))
|
||||
code.append('\tconst uint32_t* {0}ResourceSets;'.format(resource_name))
|
||||
code.append('')
|
||||
|
||||
|
||||
def append_info_resource(code, name, data, key, resource_name):
|
||||
if key in data:
|
||||
code.append('\t\t{0},'.format(str(len(data[key]))))
|
||||
code.append('\t\tg_{0}_{1}ResourceNames,'.format(name, resource_name))
|
||||
code.append('\t\tg_{0}_{1}ResourceBindings,'.format(name, resource_name))
|
||||
code.append('\t\tg_{0}_{1}ResourceCounts,'.format(name, resource_name))
|
||||
code.append('\t\tg_{0}_{1}ResourceSets,'.format(name, resource_name))
|
||||
else:
|
||||
code.append('\t\t0, 0, 0, 0, 0,')
|
||||
|
||||
|
||||
def append_info(code, name, data):
|
||||
code.append('\t{')
|
||||
code.append('\t\tg_{0}_size,'.format(name))
|
||||
code.append('\t\tg_{0}_data,'.format(name))
|
||||
|
||||
append_info_resource(code, name, data, 'separate_samplers', 'Sampler')
|
||||
append_info_resource(code, name, data, 'combined_samplers', 'CombinedSampler')
|
||||
append_info_resource(code, name, data, 'separate_images', 'SampledImage')
|
||||
append_info_resource(code, name, data, 'images', 'StorageImage')
|
||||
append_info_resource(code, name, data, 'uniform_texel_buffers', 'UniformTexelBuffer')
|
||||
append_info_resource(code, name, data, 'storage_texel_buffers', 'StorageTexelBuffer')
|
||||
append_info_resource(code, name, data, 'ubos', 'UniformBuffer')
|
||||
append_info_resource(code, name, data, 'ssbos', 'StorageBuffer')
|
||||
append_info_resource(code, name, data, 'inputs', 'InputAttachment')
|
||||
append_info_resource(code, name, data, 'acceleration_structures', 'AccelerationStructure')
|
||||
|
||||
code.append('\t},')
|
||||
|
||||
|
||||
def main(args):
|
||||
permutations = list()
|
||||
permutations.append(list())
|
||||
permutation_variables = list()
|
||||
|
||||
for definition in args.definitions:
|
||||
name, value = definition.split('=')
|
||||
|
||||
if value[0] == '{' and value[-1] == '}':
|
||||
values = value[1:-1].split(',')
|
||||
new_permutations = list()
|
||||
permutation_variables.append(name)
|
||||
|
||||
for val in values:
|
||||
for permutation in permutations:
|
||||
new_permutation = permutation.copy()
|
||||
new_permutation.append("-D{0}={1}".format(name, val))
|
||||
new_permutations.append(new_permutation)
|
||||
|
||||
permutations = new_permutations
|
||||
else:
|
||||
for permutation in permutations:
|
||||
permutation.append("-D{0}={1}".format(name, value))
|
||||
|
||||
for permutation in permutations:
|
||||
permutation.append('-e')
|
||||
permutation.append(args.entry_point)
|
||||
permutation.append('-I{0}'.format(args.includes))
|
||||
permutation.append('-S')
|
||||
permutation.append(args.stage)
|
||||
permutation.append('--target-env')
|
||||
permutation.append(args.target_env)
|
||||
|
||||
if args.undefinitions is None:
|
||||
continue
|
||||
|
||||
for undefinition in args.undefinitions:
|
||||
permutation.append("-U{0}".format(undefinition))
|
||||
|
||||
optimization = (args.optimization == 's')
|
||||
for j, file in enumerate(args.files):
|
||||
if len(args.files) == 1:
|
||||
file_name = args.name
|
||||
else:
|
||||
file_name = '{0}_{1}'.format(args.name, str(j))
|
||||
|
||||
if len(permutations) > 0:
|
||||
code_name = '{0}_permutations.h'.format(file_name)
|
||||
else:
|
||||
code_name = '{0}.h'.format(file_name)
|
||||
|
||||
code = list()
|
||||
code_path = os.path.join(args.output, code_name)
|
||||
|
||||
names = list()
|
||||
datas = list()
|
||||
for i, permutation in enumerate(permutations):
|
||||
name, data = process(file, file_name, permutation, args.output, optimization, args.reflection)
|
||||
names.append(name)
|
||||
datas.append(data)
|
||||
|
||||
for name in names:
|
||||
spirv_path = os.path.join(args.output, name + '.spv')
|
||||
if os.path.exists(spirv_path):
|
||||
os.remove(spirv_path)
|
||||
|
||||
infos = list()
|
||||
indices = [names.index(name) for name in names]
|
||||
indirections = list()
|
||||
|
||||
for i, index in enumerate(indices):
|
||||
if i == index:
|
||||
code.append('#include "{0}.h"'.format(names[index]))
|
||||
indirections.append(len(infos))
|
||||
infos.append({ 'name': names[index], 'data': datas[index] })
|
||||
else:
|
||||
indirections.append(None)
|
||||
|
||||
for i, index in enumerate(indices):
|
||||
if indirections[i] is None:
|
||||
indirections[i] = indirections[index]
|
||||
|
||||
code.append('')
|
||||
code.append('typedef union {0}_PermutationKey '.format(file_name) + '{')
|
||||
code.append('\tstruct {')
|
||||
|
||||
for variable in permutation_variables:
|
||||
code.append('\t\tuint32_t {0} : 1;'.format(variable))
|
||||
|
||||
code.append('\t};')
|
||||
code.append('\tuint32_t index;')
|
||||
code.append('}' + ' {0}_PermutationKey;'.format(file_name))
|
||||
code.append('')
|
||||
|
||||
code.append('typedef struct {0}_PermutationInfo '.format(file_name) + '{')
|
||||
code.append('\tconst uint32_t blobSize;')
|
||||
code.append('\tconst unsigned char* blobData;')
|
||||
code.append('')
|
||||
|
||||
append_resources_info(code, 'Sampler', 'sampler')
|
||||
append_resources_info(code, 'CombinedSampler', 'combinedSampler')
|
||||
append_resources_info(code, 'SampledImage', 'sampledImage')
|
||||
append_resources_info(code, 'StorageImage', 'storageImage')
|
||||
append_resources_info(code, 'UniformTexelBuffer', 'uniformTexelBuffer')
|
||||
append_resources_info(code, 'StorageTexelBuffer', 'storageTexelBuffer')
|
||||
append_resources_info(code, 'UniformBuffer', 'uniformBuffer')
|
||||
append_resources_info(code, 'StorageBuffer', 'storageBuffer')
|
||||
append_resources_info(code, 'InputAttachment', 'inputAttachment')
|
||||
append_resources_info(code, 'RTAccelerationStructure', 'rtAccelerationStructure')
|
||||
|
||||
code.append('}' + ' {0}_PermutationInfo;'.format(file_name))
|
||||
code.append('')
|
||||
|
||||
code.append('static const uint32_t g_{0}_IndirectionTable[] = '.format(file_name) + '{')
|
||||
for index in indirections:
|
||||
code.append('\t{0},'.format(index))
|
||||
code.append('};')
|
||||
code.append('')
|
||||
|
||||
code.append('static const {0}_PermutationInfo g_{0}_PermutationInfo[] = '.format(file_name) + '{')
|
||||
for info in infos:
|
||||
append_info(code, info['name'], info['data'])
|
||||
code.append('};')
|
||||
|
||||
with open(code_path, 'w') as code_file:
|
||||
code_file.write('\n'.join(code))
|
||||
|
||||
with open(code_path + '.d', 'w') as code_file:
|
||||
code_file.write('{0}:'.format(code_name))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('files', metavar='FILE', type=str, nargs='+')
|
||||
parser.add_argument('-compiler', choices=['glslang'])
|
||||
parser.add_argument('-deps', choices=['gcc'])
|
||||
parser.add_argument('-D', action='append', dest='definitions')
|
||||
parser.add_argument('-e', dest='entry_point')
|
||||
parser.add_argument('-I', dest='includes')
|
||||
parser.add_argument('-name')
|
||||
parser.add_argument('-O', choices=['d', 's'], dest='optimization')
|
||||
parser.add_argument('-output')
|
||||
parser.add_argument('-reflection', action='store_true')
|
||||
parser.add_argument('-S', dest='stage')
|
||||
parser.add_argument('--target-env', dest='target_env')
|
||||
parser.add_argument('-U', action='append', dest='undefinitions')
|
||||
main(parser.parse_args())
|
||||
|
7
tools/sc/FidelityFX_SC.sh
Executable file
7
tools/sc/FidelityFX_SC.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
### Run the original binary via wine:
|
||||
# wine $(dirname "$0")/FidelityFX_SC.exe $@
|
||||
|
||||
### Run the reverse-engineered python script:
|
||||
python $(dirname $0)/FidelityFX_SC.py $@
|
Loading…
Reference in New Issue
Block a user