Skip to content

Commit

Permalink
Merge branch 'dev/adunn/active_light_api' into 'main'
Browse files Browse the repository at this point in the history
Implement active light api for single instance, multi-scene rendering.

See merge request lightspeedrtx/dxvk-remix-nv!613
  • Loading branch information
AlexDunn committed Dec 11, 2023
2 parents 458b010 + 50231ae commit 730a73d
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 49 deletions.
5 changes: 4 additions & 1 deletion public/include/remix/remix.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ namespace remix {
Result< void > DrawInstance(const InstanceInfo& info);
Result< remixapi_LightHandle > CreateLight(const LightInfo& info);
Result< void > DestroyLight(remixapi_LightHandle handle);
Result< void > DrawLightInstance(remixapi_LightHandle handle);
Result< void > SetConfigVariable(const char* key, const char* value);

// DXVK interoperability
Expand Down Expand Up @@ -676,7 +677,9 @@ namespace remix {
return m_CInterface.DestroyLight(handle);
}


inline Result< void > Interface::DrawLightInstance(remixapi_LightHandle handle) {
return m_CInterface.DrawLightInstance(handle);
}

namespace detail {
struct dxvk_ExternalSwapchain {
Expand Down
4 changes: 4 additions & 0 deletions public/include/remix/remix_c.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,9 @@ extern "C" {
remixapi_LightHandle handle);


typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_DrawLightInstance)(
remixapi_LightHandle lightHandle);


typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_SetConfigVariable)(
const char* key,
Expand Down Expand Up @@ -511,6 +514,7 @@ extern "C" {
PFN_remixapi_DrawInstance DrawInstance;
PFN_remixapi_CreateLight CreateLight;
PFN_remixapi_DestroyLight DestroyLight;
PFN_remixapi_DrawLightInstance DrawLightInstance;
PFN_remixapi_SetConfigVariable SetConfigVariable;
// DXVK interoperability
PFN_remixapi_dxvk_CreateD3D9 dxvk_CreateD3D9;
Expand Down
11 changes: 1 addition & 10 deletions src/dxvk/rtx_render/rtx_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -995,16 +995,7 @@ namespace dxvk {
constants.isZUp = RtxOptions::Get()->isZUp();
constants.enableCullingSecondaryRays = RtxOptions::Get()->enableCullingInSecondaryRays();

// Dome light handling
DomeLight domeLight;
uint32_t domeLightTextureIndex;
if (constants.domeLightActive = getSceneManager().getLightManager().getActiveDomeLight(domeLight, domeLightTextureIndex)) {
assert(domeLightTextureIndex != UINT_MAX);

constants.domeLightTextureIndex = domeLightTextureIndex;
constants.domeLightRadiance = domeLight.radiance;
constants.worldToDomeLightTranform = domeLight.worldToLight;
}
constants.domeLightArgs = getSceneManager().getLightManager().getDomeLightArgs();

// Upload the constants to the GPU
{
Expand Down
46 changes: 36 additions & 10 deletions src/dxvk/rtx_render/rtx_light_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,11 @@ namespace dxvk {
m_linearizedLights.emplace_back(&light);
}

for (auto& [handle, light] : m_externalLights) {
m_linearizedLights.emplace_back(&light);
for (auto& handle : m_externalActiveLightList) {
auto& found = m_externalLights.find(handle);
if (found != m_externalLights.end()) {
m_linearizedLights.emplace_back(&found->second);
}
}

// Count the active light of each type
Expand Down Expand Up @@ -443,13 +446,23 @@ namespace dxvk {

// Generate a GPU dome light if necessary
DomeLight activeDomeLight;
if (getActiveDomeLight(activeDomeLight, m_activeDomeLightBindlessTextureIndex)) {
if (getActiveDomeLight(activeDomeLight)) {
// Ensures a texture stays in VidMem
SceneManager& sceneManager = device()->getCommon()->getSceneManager();
sceneManager.trackTexture(ctx, activeDomeLight.texture, m_activeDomeLightBindlessTextureIndex, true, false);
sceneManager.trackTexture(ctx, activeDomeLight.texture, m_gpuDomeLightArgs.textureIndex, true, false);

m_gpuDomeLightArgs.active = true;
m_gpuDomeLightArgs.radiance = activeDomeLight.radiance;
m_gpuDomeLightArgs.worldToLightTransform = activeDomeLight.worldToLight;
} else {
m_activeDomeLightBindlessTextureIndex = UINT_MAX;
m_gpuDomeLightArgs.active = false;
m_gpuDomeLightArgs.radiance = Vector3(0.0f);
m_gpuDomeLightArgs.textureIndex = BINDING_INDEX_INVALID;
}

// Reset external active light list.
m_externalActiveDomeLight = nullptr;
m_externalActiveLightList.clear();
}

float LightManager::isSimilar(const RtLight& a, const RtLight& b, float distanceThreshold) {
Expand Down Expand Up @@ -635,14 +648,19 @@ namespace dxvk {
m_externalDomeLights.erase(handle);
}

bool LightManager::getActiveDomeLight(DomeLight& domeLightOut, uint32_t& bindlessTextureIndexOut) const {
if (m_externalDomeLights.size() == 0) {
bool LightManager::getActiveDomeLight(DomeLight& domeLightOut) {
if (m_externalDomeLights.size() == 0 || m_externalActiveDomeLight == nullptr) {
return false;
}

auto found = m_externalDomeLights.find(m_externalActiveDomeLight);
if (found == m_externalDomeLights.end()) {
// Invalid active dome light, reset it
m_externalActiveDomeLight = nullptr;
return false;
}

// We take the first dome light
domeLightOut = m_externalDomeLights.begin()->second;
bindlessTextureIndexOut = m_activeDomeLightBindlessTextureIndex;
domeLightOut = found->second;

return true;
}
Expand All @@ -658,6 +676,14 @@ namespace dxvk {
}
}

void LightManager::addExternalLightInstance(remixapi_LightHandle enabledLight) {
if (m_externalLights.find(enabledLight) != m_externalLights.end()) {
m_externalActiveLightList.insert(enabledLight);
} else if (m_externalDomeLights.find(enabledLight) != m_externalDomeLights.end() && m_externalActiveDomeLight == nullptr) {
m_externalActiveDomeLight = enabledLight;
}
}

void LightManager::setRaytraceArgs(RaytraceArgs& raytraceArgs, uint32_t rtxdiInitialLightSamples, uint32_t volumeRISInitialLightSamples, uint32_t risLightSamples) const
{
// The algorithm below performs two tasks:
Expand Down
13 changes: 9 additions & 4 deletions src/dxvk/rtx_render/rtx_light_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "rtx_lights.h"
#include "rtx_camera_manager.h"
#include "rtx_common_object.h"
#include "rtx/pass/common_binding_indices.h"
#include "rtx/pass/raytrace_args.h"

using remixapi_LightHandle = struct remixapi_LightHandle_T*;

Expand Down Expand Up @@ -73,8 +75,7 @@ struct LightManager : public CommonDeviceObject {
const Rc<DxvkBuffer> getPreviousLightBuffer() const { return m_previousLightBuffer.ptr() ? m_previousLightBuffer : m_lightBuffer; }
const Rc<DxvkBuffer> getLightMappingBuffer() const { return m_lightMappingBuffer; }
const uint32_t getActiveCount() const { return m_currentActiveLightCount; }

bool getActiveDomeLight(DomeLight& lightOut, uint32_t& bindlessTextureIndexOut) const;
const DomeLightArgs& getDomeLightArgs() const { return m_gpuDomeLightArgs; }

void clear();

Expand All @@ -91,6 +92,7 @@ struct LightManager : public CommonDeviceObject {
void addExternalLight(remixapi_LightHandle handle, const RtLight& rtlight);
void addExternalDomeLight(remixapi_LightHandle handle, const DomeLight& domeLight);
void removeExternalLight(remixapi_LightHandle handle);
void addExternalLightInstance(remixapi_LightHandle enabledLight);

void setRaytraceArgs(RaytraceArgs& raytraceArgs, uint32_t rtxdiInitialLightSamples, uint32_t volumeRISInitialLightSamples, uint32_t risLightSamples) const;

Expand All @@ -104,12 +106,14 @@ struct LightManager : public CommonDeviceObject {
std::optional<RtLight> m_fallbackLight{};
std::unordered_map<remixapi_LightHandle, RtLight> m_externalLights;
std::unordered_map<remixapi_LightHandle, DomeLight> m_externalDomeLights;
std::unordered_set<remixapi_LightHandle> m_externalActiveLightList;
remixapi_LightHandle m_externalActiveDomeLight = nullptr;
DomeLightArgs m_gpuDomeLightArgs;

Rc<DxvkBuffer> m_lightBuffer;
Rc<DxvkBuffer> m_previousLightBuffer;
Rc<DxvkBuffer> m_lightMappingBuffer;

uint32_t m_activeDomeLightBindlessTextureIndex = UINT_MAX;

uint32_t m_currentActiveLightCount = 0;
std::array<LightRange, lightTypeCount> m_lightTypeRanges;
// Note: The following vectors are included as members rather as local variables in the
Expand All @@ -120,6 +124,7 @@ struct LightManager : public CommonDeviceObject {
std::vector<unsigned char> m_lightsGPUData{};
std::vector<uint16_t> m_lightMappingData{};

bool getActiveDomeLight(DomeLight& lightOut);

void garbageCollectionInternal();

Expand Down
23 changes: 23 additions & 0 deletions src/dxvk/rtx_render/rtx_remix_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,28 @@ namespace {
return REMIXAPI_ERROR_CODE_SUCCESS;
}


remixapi_ErrorCode REMIXAPI_CALL remixapi_DrawLightInstance(
remixapi_LightHandle lightHandle) {
dxvk::D3D9DeviceEx* remixDevice = tryAsDxvk();
if (!remixDevice) {
return REMIXAPI_ERROR_CODE_REMIX_DEVICE_WAS_NOT_REGISTERED;
}
if (!lightHandle) {
return REMIXAPI_ERROR_CODE_WRONG_ARGUMENTS;
}

// async load
std::lock_guard lock { s_mutex };
remixDevice->EmitCs([lightHandle](dxvk::DxvkContext* ctx) {
auto& lightMgr = ctx->getCommonObjects()->getSceneManager().getLightManager();
lightMgr.addExternalLightInstance(lightHandle);
});

return REMIXAPI_ERROR_CODE_SUCCESS;
}


remixapi_ErrorCode REMIXAPI_CALL remixapi_SetConfigVariable(
const char* key,
const char* value) {
Expand Down Expand Up @@ -1090,6 +1112,7 @@ extern "C"
interf.DrawInstance = remixapi_DrawInstance;
interf.CreateLight = remixapi_CreateLight;
interf.DestroyLight = remixapi_DestroyLight;
interf.DrawLightInstance = remixapi_DrawLightInstance;
interf.SetConfigVariable = remixapi_SetConfigVariable;
interf.dxvk_CreateD3D9 = remixapi_dxvk_CreateD3D9;
interf.dxvk_RegisterD3D9Device = remixapi_dxvk_RegisterD3D9Device;
Expand Down
24 changes: 10 additions & 14 deletions src/dxvk/shaders/rtx/algorithm/geometry_resolver.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -1083,18 +1083,16 @@ void geometryResolverVertex(
}
else
{
if(cb.domeLightActive)
if(cb.domeLightArgs.active)
{
float3 domeSampleDirection = mul(cb.worldToDomeLightTranform, float4(geometryResolverState.direction, 0.0f)).xyz;
float2 sampleUV = cartesianDirectionToLatLongSphere(domeSampleDirection);
emissiveRadiance += cb.domeLightRadiance * textures[nonuniformEXT(uint(cb.domeLightTextureIndex))].SampleLevel(LinearWrapSampler, sampleUV, 0).xyz;
emissiveRadiance += cb.domeLightArgs.radiance * sampleDomeLightTexture(LinearWrapSampler, geometryResolverState.direction, cb.domeLightArgs.textureIndex, cb.domeLightArgs.worldToLightTransform);
}
else
{
// Apply sky radiance on miss
// TODO: add jitter?
vec2 screenUV = cameraPixelCoordinateToScreenUV(cb.camera, geometryResolverState.pixelCoordinate);
emissiveRadiance += cb.skyBrightness * SkyMatte.Sample(screenUV);
// Apply sky radiance on miss
// TODO: add jitter?
vec2 screenUV = cameraPixelCoordinateToScreenUV(cb.camera, geometryResolverState.pixelCoordinate);
emissiveRadiance += cb.skyBrightness * SkyMatte.Sample(screenUV);
}
}

Expand Down Expand Up @@ -1568,16 +1566,14 @@ void geometryPSRResolverVertex(
}
else
{
if(cb.domeLightActive)
if(cb.domeLightArgs.active)
{
float3 domeSampleDirection = mul(cb.worldToDomeLightTranform, float4(ray.direction, 0.0f)).xyz;
float2 sampleUV = cartesianDirectionToLatLongSphere(domeSampleDirection);
emissiveRadiance += cb.domeLightRadiance * textures[nonuniformEXT(uint(cb.domeLightTextureIndex))].SampleLevel(LinearWrapSampler, sampleUV, 0).xyz;
emissiveRadiance += cb.domeLightArgs.radiance * sampleDomeLightTexture(LinearWrapSampler, ray.direction, cb.domeLightArgs.textureIndex, cb.domeLightArgs.worldToLightTransform);
}
else
{
// Output radiance from sky probe
emissiveRadiance += cb.skyBrightness * SkyProbe.Sample(ray.direction);
// Output radiance from sky probe
emissiveRadiance += cb.skyBrightness * SkyProbe.Sample(ray.direction);
}
}

Expand Down
8 changes: 3 additions & 5 deletions src/dxvk/shaders/rtx/algorithm/integrator_indirect.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,13 @@ void integratePathVertex(
// Note: True misses going out into infinity will have no hit in the ray interaction and the continue resolving flag set to false. This is in contrast to misses
// which may require further resolving which may be needed in cases of skipping specific pieces of geometry while still wishing to continue traversal.

if(cb.domeLightActive)
if(cb.domeLightArgs.active)
{
float3 domeSampleDirection = mul(cb.worldToDomeLightTranform, float4(ray.direction, 0.0f)).xyz;
float2 sampleUV = cartesianDirectionToLatLongSphere(domeSampleDirection);
emissiveRadiance += cb.domeLightRadiance * textures[nonuniformEXT(uint(cb.domeLightTextureIndex))].SampleLevel(LinearWrapSampler, sampleUV, 0).xyz;
emissiveRadiance += cb.domeLightArgs.radiance * sampleDomeLightTexture(LinearWrapSampler, pathState.direction, cb.domeLightArgs.textureIndex, cb.domeLightArgs.worldToLightTransform);
}
else
{
emissiveRadiance += cb.skyBrightness * SkyProbe.Sample(pathState.direction);
emissiveRadiance += cb.skyBrightness * SkyProbe.Sample(pathState.direction);
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/dxvk/shaders/rtx/concept/light/light_helper.slangh
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,15 @@ struct LightSample
// Note: 32 bit floating point used to avoid precision issues with some kinds of sampling on lights.
float solidAnglePdf;
};

float3 sampleDomeLightTexture(SamplerState sampler, float3 worldDirection, uint32_t domeLightTextureIndex, float4x4 worldToDomeLightTransform)
{
if(domeLightTextureIndex == BINDING_INDEX_INVALID)
{
return 1..xxx;
}

float3 domeSampleDirection = mul(worldToDomeLightTransform, float4(worldDirection, 0.0f)).xyz;
float2 sampleUV = cartesianDirectionToLatLongSphere(domeSampleDirection);
return textures[nonuniformEXT(uint(domeLightTextureIndex))].SampleLevel(sampler, sampleUV, 0).xyz;
}
15 changes: 10 additions & 5 deletions src/dxvk/shaders/rtx/pass/raytrace_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ struct NeeCacheArgs {
uint clearCache;
};

struct DomeLightArgs {
mat4 worldToLightTransform;

vec3 radiance;
uint active;

uint textureIndex;
};

// Constant buffer
struct RaytraceArgs {
Camera camera;
Expand Down Expand Up @@ -296,11 +305,7 @@ struct RaytraceArgs {
uint thinOpaqueEnable;
float totalMipBias;

mat4 worldToDomeLightTranform;

vec3 domeLightRadiance;
uint domeLightActive;
DomeLightArgs domeLightArgs;

uint domeLightTextureIndex;
float2 upscaleFactor; // Displayed(upscaled) / RT resolution
};

0 comments on commit 730a73d

Please sign in to comment.