Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions public/include/remix/remix.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -173,6 +173,8 @@ namespace remix {
Result< void > DestroyLight(remixapi_LightHandle handle);
Result< void > DrawLightInstance(remixapi_LightHandle handle);
Result< void > SetConfigVariable(const char* key, const char* value);
Result< void > AddTextureHash(const char* textureCategory, const char* textureHash);
Result< void > RemoveTextureHash(const char* textureCategory, const char* textureHash);

// DXVK interoperability
Result< IDirect3D9Ex* > dxvk_CreateD3D9(bool editorModeEnabled = false);
Expand Down Expand Up @@ -208,7 +210,7 @@ namespace remix {
return status;
}

static_assert(sizeof(remixapi_Interface) == 168,
static_assert(sizeof(remixapi_Interface) == 184,
"Change version, update C++ wrapper when adding new functions");

remix::Interface interfaceInCpp = {};
Expand Down Expand Up @@ -251,6 +253,20 @@ namespace remix {
return m_CInterface.SetConfigVariable(key, value);
}

inline Result< void > Interface::AddTextureHash(const char* textureCategory, const char* textureHash) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arguments we used for SetConfigVariable are actually something we regret, and we'd like to avoid repeating the same mistake. Primarily, in that it would be a breaking change to add any more arguments.

Instead of AddTextureHash and RemoveTextureHash, we'd prefer to see a ModifyRtxOption function that takes in a struct. That struct can be extended without breaking backwards compatibility, and could have fields for adding & removing values from a HashSet.

typedef struct remixapi_ModifyRtxOptionArgs {
    remixapi_StructType sType;
    void*          pNext;
    const char* rtxOptionName;
    const char* newValue;

    // Hash value to add or remove.  Only used if `rtxOptionName` is a HashSet and `newValue` is a nullptr.
    // Value of 0 is a no-op.
    uint64_t       hashToAdd;
    uint64_t       hashToRemove;
} remixapi_ModifyRtxOptionArgs;

May also be a good idea to define a REMIXAPI_EMPTY_HASH that's set to 0 somewhere in the API, instead of just having 0 as a magic value in that comment.

There may be a better way to encode newValue that would support actual int/float/etc values, but

if (!m_CInterface.AddTextureHash) {
return REMIXAPI_ERROR_CODE_NOT_INITIALIZED;
}
return m_CInterface.AddTextureHash(textureCategory, textureHash);
}

inline Result< void > Interface::RemoveTextureHash(const char* textureCategory, const char* textureHash) {
if (!m_CInterface.RemoveTextureHash) {
return REMIXAPI_ERROR_CODE_NOT_INITIALIZED;
}
return m_CInterface.RemoveTextureHash(textureCategory, textureHash);
}

inline Result< void > Interface::Present(const remixapi_PresentInfo* info) {
if (!m_CInterface.Present) {
return REMIXAPI_ERROR_CODE_NOT_INITIALIZED;
Expand Down
42 changes: 26 additions & 16 deletions public/include/remix/remix_c.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -53,7 +53,7 @@
#define REMIXAPI_VERSION_GET_PATCH(version) (((uint64_t)(version) ) & (uint64_t)0xFFFF)

#define REMIXAPI_VERSION_MAJOR 0
#define REMIXAPI_VERSION_MINOR 5
#define REMIXAPI_VERSION_MINOR 6
#define REMIXAPI_VERSION_PATCH 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

patch version should be reset, since you bumped the minor version. (0.5.1 becomes 0.6.0, not 0.6.1)



Expand Down Expand Up @@ -400,20 +400,20 @@ extern "C" {
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_ANTI_CULLING = 1 << 5,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_MOTION_BLUR = 1 << 6,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_OPACITY_MICROMAP = 1 << 7,
REMIXAPI_INSTANCE_CATEGORY_BIT_HIDDEN = 1 << 8,
REMIXAPI_INSTANCE_CATEGORY_BIT_PARTICLE = 1 << 9,
REMIXAPI_INSTANCE_CATEGORY_BIT_BEAM = 1 << 10,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_STATIC = 1 << 11,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_DYNAMIC = 1 << 12,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_SINGLE_OFFSET = 1 << 13,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_NO_OFFSET = 1 << 14,
REMIXAPI_INSTANCE_CATEGORY_BIT_ALPHA_BLEND_TO_CUTOUT = 1 << 15,
REMIXAPI_INSTANCE_CATEGORY_BIT_TERRAIN = 1 << 16,
REMIXAPI_INSTANCE_CATEGORY_BIT_ANIMATED_WATER = 1 << 17,
REMIXAPI_INSTANCE_CATEGORY_BIT_THIRD_PERSON_PLAYER_MODEL = 1 << 18,
REMIXAPI_INSTANCE_CATEGORY_BIT_THIRD_PERSON_PLAYER_BODY = 1 << 19,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_BAKED_LIGHTING = 1 << 20,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_ALPHA_CHANNEL = 1 << 21,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_ALPHA_CHANNEL = 1 << 8,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the order like this will break any existing uses. I know it's just making it match the order of InstanceCategories in the runtime, but making the code slightly nicer isn't a good reason to introduce a breaking change to the API.

REMIXAPI_INSTANCE_CATEGORY_BIT_HIDDEN = 1 << 9,
REMIXAPI_INSTANCE_CATEGORY_BIT_PARTICLE = 1 << 10,
REMIXAPI_INSTANCE_CATEGORY_BIT_BEAM = 1 << 11,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_STATIC = 1 << 12,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_DYNAMIC = 1 << 13,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_SINGLE_OFFSET = 1 << 14,
REMIXAPI_INSTANCE_CATEGORY_BIT_DECAL_NO_OFFSET = 1 << 15,
REMIXAPI_INSTANCE_CATEGORY_BIT_ALPHA_BLEND_TO_CUTOUT = 1 << 16,
REMIXAPI_INSTANCE_CATEGORY_BIT_TERRAIN = 1 << 17,
REMIXAPI_INSTANCE_CATEGORY_BIT_ANIMATED_WATER = 1 << 18,
REMIXAPI_INSTANCE_CATEGORY_BIT_THIRD_PERSON_PLAYER_MODEL = 1 << 19,
REMIXAPI_INSTANCE_CATEGORY_BIT_THIRD_PERSON_PLAYER_BODY = 1 << 20,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_BAKED_LIGHTING = 1 << 21,
REMIXAPI_INSTANCE_CATEGORY_BIT_IGNORE_TRANSPARENCY_LAYER = 1 << 22,
} remixapi_InstanceCategoryBit;

Expand Down Expand Up @@ -562,6 +562,14 @@ extern "C" {
const char* key,
const char* value);

typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_AddTextureHash)(
const char* textureCategory,
const char* textureHash);

typedef remixapi_ErrorCode(REMIXAPI_PTR* PFN_remixapi_RemoveTextureHash)(
const char* textureCategory,
const char* textureHash);

typedef struct remixapi_PresentInfo {
remixapi_StructType sType;
void* pNext;
Expand Down Expand Up @@ -642,6 +650,8 @@ extern "C" {
PFN_remixapi_DestroyLight DestroyLight;
PFN_remixapi_DrawLightInstance DrawLightInstance;
PFN_remixapi_SetConfigVariable SetConfigVariable;
PFN_remixapi_AddTextureHash AddTextureHash;
PFN_remixapi_RemoveTextureHash RemoveTextureHash;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New functions need to be declared at the end of the struct to preserve backwards compatibility


// DXVK interoperability
PFN_remixapi_dxvk_CreateD3D9 dxvk_CreateD3D9;
Expand Down
74 changes: 73 additions & 1 deletion src/dxvk/rtx_render/rtx_remix_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,76 @@ namespace {
return REMIXAPI_ERROR_CODE_SUCCESS;
}

remixapi_ErrorCode REMIXAPI_CALL remixapi_AddTextureHash(
const char* textureCategory,
const char* textureHash) {
std::lock_guard lock { s_mutex };

if (!textureCategory || textureCategory[0] == '\0' || !textureHash) {
return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS;
}

std::string strCategory = std::string { textureCategory };
const auto& globalRtxOptions = dxvk::RtxOptionImpl::getGlobalRtxOptionMap();
const XXH64_hash_t optionHash = dxvk::StringToXXH64(strCategory, 0);
auto found = globalRtxOptions.find(optionHash);
if (found == globalRtxOptions.end()) {
return REMIXAPI_ERROR_CODE_GENERAL_FAILURE;
}

if (found->second->type != dxvk::OptionType::HashSet) {
return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS;
}

auto& textureSet = *found->second->valueList[(int) dxvk::RtxOptionImpl::ValueType::Value].hashSet;

const XXH64_hash_t h = std::stoull(textureHash, nullptr, 16);
const auto textureIterator = textureSet.find(h);

if (textureIterator == textureSet.end()) {
textureSet.insert(h);
} else {
return REMIXAPI_ERROR_CODE_SUCCESS; // already exists
}

return REMIXAPI_ERROR_CODE_SUCCESS;
}

remixapi_ErrorCode REMIXAPI_CALL remixapi_RemoveTextureHash(
const char* textureCategory,
const char* textureHash) {
std::lock_guard lock { s_mutex };

if (!textureCategory || textureCategory[0] == '\0' || !textureHash) {
return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS;
}

std::string strCategory = std::string { textureCategory };
const auto& globalRtxOptions = dxvk::RtxOptionImpl::getGlobalRtxOptionMap();
const XXH64_hash_t optionHash = dxvk::StringToXXH64(strCategory, 0);
auto found = globalRtxOptions.find(optionHash);
if (found == globalRtxOptions.end()) {
return REMIXAPI_ERROR_CODE_GENERAL_FAILURE;
}

if (found->second->type != dxvk::OptionType::HashSet) {
return REMIXAPI_ERROR_CODE_INVALID_ARGUMENTS;
}

auto& textureSet = *found->second->valueList[(int) dxvk::RtxOptionImpl::ValueType::Value].hashSet;

const XXH64_hash_t h = std::stoull(textureHash, nullptr, 16);
const auto textureIterator = textureSet.find(h);

if (textureIterator != textureSet.end()) {
textureSet.erase(textureIterator);
} else {
return REMIXAPI_ERROR_CODE_SUCCESS; // does not exist
}

return REMIXAPI_ERROR_CODE_SUCCESS;
}

remixapi_ErrorCode REMIXAPI_CALL remixapi_pick_RequestObjectPicking(
const remixapi_Rect2D* pixelRegion,
PFN_remixapi_pick_RequestObjectPickingUserCallback callback,
Expand Down Expand Up @@ -1497,6 +1567,8 @@ extern "C"
interf.DestroyLight = remixapi_DestroyLight;
interf.DrawLightInstance = remixapi_DrawLightInstance;
interf.SetConfigVariable = remixapi_SetConfigVariable;
interf.AddTextureHash = remixapi_AddTextureHash;
interf.RemoveTextureHash = remixapi_RemoveTextureHash;
interf.dxvk_CreateD3D9 = remixapi_dxvk_CreateD3D9_legacy;
interf.dxvk_RegisterD3D9Device = remixapi_dxvk_RegisterD3D9Device;
interf.dxvk_GetExternalSwapchain = remixapi_dxvk_GetExternalSwapchain;
Expand All @@ -1506,7 +1578,7 @@ extern "C"
interf.pick_RequestObjectPicking = remixapi_pick_RequestObjectPicking;
interf.pick_HighlightObjects = remixapi_pick_HighlightObjects;
}
static_assert(sizeof(interf) == 168, "Add/remove function registration");
static_assert(sizeof(interf) == 184, "Add/remove function registration");

*out_result = interf;
return REMIXAPI_ERROR_CODE_SUCCESS;
Expand Down