Skip to content

Commit f3cfd26

Browse files
committed
Add support for static samplers in pipeline layout creation in D3D12/Vulkan
1 parent b88548d commit f3cfd26

File tree

11 files changed

+272
-97
lines changed

11 files changed

+272
-97
lines changed

include/reshade.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <Windows.h>
1212

1313
// Current version of the ReShade API
14-
#define RESHADE_API_VERSION 12
14+
#define RESHADE_API_VERSION 13
1515

1616
// Optionally import ReShade API functions when 'RESHADE_API_LIBRARY' is defined instead of using header-only mode
1717
#if defined(RESHADE_API_LIBRARY) || defined(RESHADE_API_LIBRARY_EXPORT)

include/reshade_api_pipeline.hpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,10 @@ namespace reshade { namespace api
121121
{
122122
push_constants = 1,
123123
descriptor_table = 0,
124+
descriptor_table_with_static_samplers = 4,
124125
push_descriptors = 2,
125-
push_descriptors_with_ranges = 3
126+
push_descriptors_with_ranges = 3,
127+
push_descriptors_with_static_samplers = 5
126128
};
127129

128130
/// <summary>
@@ -190,6 +192,13 @@ namespace reshade { namespace api
190192
/// </summary>
191193
descriptor_type type = descriptor_type::sampler;
192194
};
195+
struct descriptor_range_with_static_samplers : public descriptor_range
196+
{
197+
/// <summary>
198+
/// Optional array of sampler descriptions to statically embed into the descriptor table when the descriptor type is <see cref="descriptor_type::sampler"/> or <see cref="descriptor_type::sampler_with_resource_view"/>.
199+
/// </summary>
200+
const sampler_desc *static_samplers = nullptr;
201+
};
193202

194203
/// <summary>
195204
/// Describes a single parameter in a pipeline layout.
@@ -199,7 +208,9 @@ namespace reshade { namespace api
199208
constexpr pipeline_layout_param() : push_descriptors() {}
200209
constexpr pipeline_layout_param(const constant_range &push_constants) : type(pipeline_layout_param_type::push_constants), push_constants(push_constants) {}
201210
constexpr pipeline_layout_param(const descriptor_range &push_descriptors) : type(pipeline_layout_param_type::push_descriptors), push_descriptors(push_descriptors) {}
211+
constexpr pipeline_layout_param(const descriptor_range_with_static_samplers &push_descriptors) : type(pipeline_layout_param_type::push_descriptors_with_static_samplers), descriptor_table_with_static_samplers({ 1, &push_descriptors }) {}
202212
constexpr pipeline_layout_param(uint32_t count, const descriptor_range *ranges) : type(pipeline_layout_param_type::descriptor_table), descriptor_table({ count, ranges }) {}
213+
constexpr pipeline_layout_param(uint32_t count, const descriptor_range_with_static_samplers *ranges) : type(pipeline_layout_param_type::descriptor_table_with_static_samplers), descriptor_table_with_static_samplers({ count, ranges }) {}
203214

204215
/// <summary>
205216
/// Type of the parameter.
@@ -226,6 +237,15 @@ namespace reshade { namespace api
226237
uint32_t count;
227238
const descriptor_range *ranges;
228239
} descriptor_table;
240+
241+
/// <summary>
242+
/// Used when parameter type is <see cref="pipeline_layout_param_type::descriptor_table_with_static_samplers"/> or <see cref="pipeline_layout_param_type::push_descriptors_with_static_samplers"/>.
243+
/// </summary>
244+
struct
245+
{
246+
uint32_t count;
247+
const descriptor_range_with_static_samplers *ranges;
248+
} descriptor_table_with_static_samplers;
229249
};
230250
};
231251

source/d3d10/d3d10_impl_device.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,8 @@ bool reshade::d3d10::device_impl::create_pipeline_layout(uint32_t param_count, c
924924
if (merged_range.dx_register_space != 0)
925925
return false;
926926
break;
927+
default:
928+
return false;
927929
}
928930
}
929931

source/d3d11/d3d11_impl_device.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,8 @@ bool reshade::d3d11::device_impl::create_pipeline_layout(uint32_t param_count, c
11641164
if (merged_range.dx_register_space != 0)
11651165
return false;
11661166
break;
1167+
default:
1168+
return false;
11671169
}
11681170
}
11691171

source/d3d12/d3d12_device.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2602,10 +2602,13 @@ bool D3D12Device::invoke_create_and_init_pipeline_layout_event(UINT node_mask, c
26022602
blob = data_mem.data();
26032603
}
26042604

2605+
bool modified = false;
26052606
// Parse DXBC root signature, convert it and call descriptor table and pipeline layout events
26062607
uint32_t param_count = 0;
26072608
std::vector<reshade::api::pipeline_layout_param> params;
26082609
std::vector<std::vector<reshade::api::descriptor_range>> ranges;
2610+
std::vector<reshade::api::descriptor_range_with_static_samplers> ranges_with_static_samplers;
2611+
std::vector<reshade::api::sampler_desc> static_samplers;
26092612

26102613
if (const auto part = static_cast<uint32_t *>(const_cast<void *>(
26112614
find_dxbc_part(
@@ -2759,41 +2762,43 @@ bool D3D12Device::invoke_create_and_init_pipeline_layout_event(UINT node_mask, c
27592762
{
27602763
const uint32_t param_index = param_count++;
27612764
params.emplace_back(); // Static samplers do not count towards the root signature size limit
2762-
ranges.emplace_back();
27632765

2764-
ranges[param_index].resize(sampler_count);
2766+
ranges_with_static_samplers.resize(sampler_count);
2767+
static_samplers.resize(sampler_count);
27652768

27662769
auto sampler_data = reinterpret_cast<D3D12_STATIC_SAMPLER_DESC *>(part + (sampler_offset / sizeof(uint32_t)));
27672770

27682771
for (uint32_t sampler_index = 0; sampler_index < sampler_count; ++sampler_index)
27692772
{
2770-
auto desc = reshade::d3d12::convert_sampler_desc(sampler_data[sampler_index]);
2773+
reshade::api::sampler_desc &desc = static_samplers[sampler_index] = reshade::d3d12::convert_sampler_desc(sampler_data[sampler_index]);
27712774

27722775
if (reshade::invoke_addon_event<reshade::addon_event::create_sampler>(this, desc))
27732776
{
27742777
reshade::d3d12::convert_sampler_desc(desc, sampler_data[sampler_index]);
2778+
modified = true; // Force pipeline layout creation with the modified description
27752779
}
27762780

2777-
reshade::api::descriptor_range &range = ranges[param_index][sampler_index];
2781+
reshade::api::descriptor_range_with_static_samplers &range = ranges_with_static_samplers[sampler_index];
27782782
range.binding = sampler_index;
27792783
range.dx_register_index = sampler_data[sampler_index].ShaderRegister;
27802784
range.dx_register_space = sampler_data[sampler_index].RegisterSpace;
27812785
range.count = 1;
27822786
range.visibility = reshade::d3d12::convert_shader_visibility(sampler_data[sampler_index].ShaderVisibility);
27832787
range.type = reshade::api::descriptor_type::sampler;
2788+
range.static_samplers = &desc;
27842789
}
27852790

2786-
params[param_index].type = reshade::api::pipeline_layout_param_type::descriptor_table;
2787-
params[param_index].descriptor_table.count = sampler_count;
2788-
params[param_index].descriptor_table.ranges = ranges[param_index].data();
2791+
params[param_index].type = reshade::api::pipeline_layout_param_type::push_descriptors_with_static_samplers;
2792+
params[param_index].descriptor_table_with_static_samplers.count = sampler_count;
2793+
params[param_index].descriptor_table_with_static_samplers.ranges = ranges_with_static_samplers.data();
27892794
}
27902795
}
27912796
}
27922797

27932798
reshade::api::pipeline_layout_param *param_data = params.data();
27942799

2795-
if (param_count != 0 &&
2796-
reshade::invoke_addon_event<reshade::addon_event::create_pipeline_layout>(this, param_count, param_data))
2800+
if (param_count != 0 && (
2801+
reshade::invoke_addon_event<reshade::addon_event::create_pipeline_layout>(this, param_count, param_data) || modified))
27972802
{
27982803
reshade::api::pipeline_layout layout;
27992804
hr = device_impl::create_pipeline_layout(param_count, param_data, &layout) ? S_OK : E_FAIL;

source/d3d12/d3d12_impl_device.cpp

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,7 @@ bool reshade::d3d12::device_impl::create_pipeline_layout(uint32_t param_count, c
12611261

12621262
std::vector<D3D12_ROOT_PARAMETER> internal_params(param_count);
12631263
std::vector<std::vector<D3D12_DESCRIPTOR_RANGE>> internal_ranges(param_count);
1264+
std::vector<D3D12_STATIC_SAMPLER_DESC> internal_static_samplers;
12641265
const auto set_ranges = new std::pair<D3D12_DESCRIPTOR_HEAP_TYPE, UINT>[param_count];
12651266

12661267
for (uint32_t i = 0; i < param_count; ++i)
@@ -1272,11 +1273,12 @@ bool reshade::d3d12::device_impl::create_pipeline_layout(uint32_t param_count, c
12721273
if (params[i].type != api::pipeline_layout_param_type::push_constants)
12731274
{
12741275
bool push_descriptors = (params[i].type == api::pipeline_layout_param_type::push_descriptors);
1275-
const uint32_t range_count = push_descriptors ? 1 : params[i].descriptor_table.count;
1276-
const api::descriptor_range *const input_ranges = push_descriptors ? &params[i].push_descriptors : params[i].descriptor_table.ranges;
1277-
push_descriptors |= (params[i].type == api::pipeline_layout_param_type::push_descriptors_with_ranges);
1276+
const bool with_static_samplers = (params[i].type == api::pipeline_layout_param_type::descriptor_table_with_static_samplers || params[i].type == api::pipeline_layout_param_type::push_descriptors_with_static_samplers);
1277+
const uint32_t range_count = push_descriptors ? 1 : with_static_samplers ? params[i].descriptor_table_with_static_samplers.count : params[i].descriptor_table.count;
1278+
const api::descriptor_range_with_static_samplers *range = static_cast<const api::descriptor_range_with_static_samplers *>(push_descriptors ? &params[i].push_descriptors : with_static_samplers ? params[i].descriptor_table_with_static_samplers.ranges : params[i].descriptor_table.ranges);
1279+
push_descriptors |= (params[i].type == api::pipeline_layout_param_type::push_descriptors_with_ranges || params[i].type == api::pipeline_layout_param_type::push_descriptors_with_static_samplers);
12781280

1279-
if (range_count == 0 || input_ranges[0].count == 0)
1281+
if (range_count == 0 || range->count == 0)
12801282
{
12811283
// Dummy parameter (to prevent root signature creation from failing)
12821284
internal_params[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
@@ -1286,15 +1288,15 @@ bool reshade::d3d12::device_impl::create_pipeline_layout(uint32_t param_count, c
12861288
continue;
12871289
}
12881290

1289-
const D3D12_DESCRIPTOR_HEAP_TYPE heap_type = convert_descriptor_type_to_heap_type(input_ranges[0].type);
1291+
const D3D12_DESCRIPTOR_HEAP_TYPE heap_type = convert_descriptor_type_to_heap_type(range->type);
12901292
set_ranges[i].first = heap_type;
12911293

1292-
if (push_descriptors && range_count == 1 && input_ranges->binding == 0 && input_ranges->count == 1 &&
1294+
if (push_descriptors && range_count == 1 && range->binding == 0 && range->count == 1 &&
12931295
heap_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV &&
1294-
input_ranges->type != api::descriptor_type::texture_shader_resource_view &&
1295-
input_ranges->type != api::descriptor_type::texture_unordered_access_view)
1296+
range->type != api::descriptor_type::texture_shader_resource_view &&
1297+
range->type != api::descriptor_type::texture_unordered_access_view)
12961298
{
1297-
switch (input_ranges->type)
1299+
switch (range->type)
12981300
{
12991301
case api::descriptor_type::constant_buffer:
13001302
internal_params[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
@@ -1310,36 +1312,69 @@ bool reshade::d3d12::device_impl::create_pipeline_layout(uint32_t param_count, c
13101312
return false;
13111313
}
13121314

1313-
internal_params[i].Descriptor.ShaderRegister = input_ranges->dx_register_index;
1314-
internal_params[i].Descriptor.RegisterSpace = input_ranges->dx_register_space;
1315+
internal_params[i].Descriptor.ShaderRegister = range->dx_register_index;
1316+
internal_params[i].Descriptor.RegisterSpace = range->dx_register_space;
13151317

1316-
visibility_mask = input_ranges->visibility;
1318+
visibility_mask = range->visibility;
13171319
}
13181320
else
13191321
{
13201322
internal_ranges[i].reserve(range_count);
13211323

1322-
for (uint32_t k = 0; k < range_count; ++k)
1324+
for (uint32_t k = 0; k < range_count; ++k, range = (with_static_samplers ? range + 1 : reinterpret_cast<const api::descriptor_range_with_static_samplers *>(reinterpret_cast<const api::descriptor_range *>(range) + 1)))
13231325
{
1324-
const api::descriptor_range &range = input_ranges[k];
1326+
assert(range->array_size <= 1);
13251327

1326-
assert(range.array_size <= 1);
1328+
if (with_static_samplers && range->type == api::descriptor_type::sampler && range->static_samplers != nullptr)
1329+
{
1330+
for (uint32_t j = 0; j < range->count; ++j)
1331+
{
1332+
D3D12_STATIC_SAMPLER_DESC &internal_static_sampler = internal_static_samplers.emplace_back();
1333+
convert_sampler_desc(range->static_samplers[j], internal_static_sampler);
1334+
1335+
internal_static_sampler.ShaderRegister = range->dx_register_index + j;
1336+
internal_static_sampler.RegisterSpace = range->dx_register_space;
1337+
1338+
switch (range->visibility)
1339+
{
1340+
default:
1341+
internal_static_sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
1342+
break;
1343+
case api::shader_stage::vertex:
1344+
internal_static_sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
1345+
break;
1346+
case api::shader_stage::hull:
1347+
internal_static_sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_HULL;
1348+
break;
1349+
case api::shader_stage::domain:
1350+
internal_static_sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_DOMAIN;
1351+
break;
1352+
case api::shader_stage::geometry:
1353+
internal_static_sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_GEOMETRY;
1354+
break;
1355+
case api::shader_stage::pixel:
1356+
internal_static_sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
1357+
break;
1358+
}
1359+
}
1360+
continue;
1361+
}
13271362

13281363
D3D12_DESCRIPTOR_RANGE &internal_range = internal_ranges[i].emplace_back();
1329-
internal_range.RangeType = convert_descriptor_type(range.type);
1330-
internal_range.NumDescriptors = range.count;
1331-
internal_range.BaseShaderRegister = range.dx_register_index;
1332-
internal_range.RegisterSpace = range.dx_register_space;
1333-
internal_range.OffsetInDescriptorsFromTableStart = range.binding;
1364+
internal_range.RangeType = convert_descriptor_type(range->type);
1365+
internal_range.NumDescriptors = range->count;
1366+
internal_range.BaseShaderRegister = range->dx_register_index;
1367+
internal_range.RegisterSpace = range->dx_register_space;
1368+
internal_range.OffsetInDescriptorsFromTableStart = range->binding;
13341369

1335-
visibility_mask |= range.visibility;
1370+
visibility_mask |= range->visibility;
13361371

13371372
// Cannot mix different descriptor heap types in a single descriptor table
1338-
if (convert_descriptor_type_to_heap_type(range.type) != heap_type)
1373+
if (convert_descriptor_type_to_heap_type(range->type) != heap_type)
13391374
return false;
13401375

1341-
if (range.count != UINT32_MAX) // Don't count unbounded ranges
1342-
set_ranges[i].second = std::max(set_ranges[i].second, range.binding + range.count);
1376+
if (range->count != UINT32_MAX) // Don't count unbounded ranges
1377+
set_ranges[i].second = std::max(set_ranges[i].second, range->binding + range->count);
13431378
}
13441379

13451380
internal_params[i].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
@@ -1388,6 +1423,8 @@ bool reshade::d3d12::device_impl::create_pipeline_layout(uint32_t param_count, c
13881423
internal_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
13891424
internal_desc.NumParameters = param_count;
13901425
internal_desc.pParameters = internal_params.data();
1426+
internal_desc.NumStaticSamplers = static_cast<uint32_t>(internal_static_samplers.size());
1427+
internal_desc.pStaticSamplers = internal_static_samplers.data();
13911428

13921429
com_ptr<ID3DBlob> signature_blob, error_blob;
13931430
com_ptr<ID3D12RootSignature> signature;

source/d3d9/d3d9_impl_device.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,8 @@ bool reshade::d3d9::device_impl::create_pipeline_layout(uint32_t param_count, co
17431743
if (merged_range.dx_register_space != 0)
17441744
return false;
17451745
break;
1746+
default:
1747+
return false;
17461748
}
17471749
}
17481750

source/opengl/opengl_impl_device.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,6 +2087,8 @@ bool reshade::opengl::device_impl::create_pipeline_layout(uint32_t param_count,
20872087
case api::pipeline_layout_param_type::push_constants:
20882088
merged_range.binding = params[i].push_constants.binding;
20892089
break;
2090+
default:
2091+
return false;
20902092
}
20912093
}
20922094

0 commit comments

Comments
 (0)