diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aef31e4fde..9a044fb91e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,8 @@ on: branches: - "main" +permissions: {} + jobs: build: runs-on: windows-2022 diff --git a/ReShade.vcxproj b/ReShade.vcxproj index 248bb7f565..1948e3e867 100644 --- a/ReShade.vcxproj +++ b/ReShade.vcxproj @@ -45,7 +45,7 @@ {0401ADF5-D085-4A3D-95B2-D9B7896BB338} Win32Proj - 10.0.17763.0 + 10.0.19041.0 10.0 @@ -266,7 +266,7 @@ Fast false true - /Zc:threadSafeInit- /utf-8 %(AdditionalOptions) + /utf-8 %(AdditionalOptions) /Zc:char8_t- %(AdditionalOptions) @@ -308,7 +308,7 @@ Fast false true - /Zc:threadSafeInit- /utf-8 %(AdditionalOptions) + /utf-8 %(AdditionalOptions) /Zc:char8_t- %(AdditionalOptions) @@ -349,7 +349,7 @@ Fast false true - /Zc:threadSafeInit- /utf-8 %(AdditionalOptions) + /utf-8 %(AdditionalOptions) /Zc:char8_t- %(AdditionalOptions) @@ -389,7 +389,7 @@ Fast false true - /Zc:threadSafeInit- /utf-8 %(AdditionalOptions) + /utf-8 %(AdditionalOptions) /Zc:char8_t- %(AdditionalOptions) @@ -430,7 +430,7 @@ Fast false true - /Zc:threadSafeInit- /utf-8 %(AdditionalOptions) + /utf-8 %(AdditionalOptions) /Zc:char8_t- %(AdditionalOptions) @@ -475,7 +475,7 @@ Fast false true - /Zc:threadSafeInit- /utf-8 %(AdditionalOptions) + /utf-8 %(AdditionalOptions) /Zc:char8_t- %(AdditionalOptions) @@ -634,8 +634,12 @@ _X86_;%(PreprocessorDefinitions) _AMD64_;%(PreprocessorDefinitions) - - + + /Zc:threadSafeInit- %(AdditionalOptions) + + + /Zc:threadSafeInit- %(AdditionalOptions) + diff --git a/ReShadeFX.vcxproj b/ReShadeFX.vcxproj index 88049761a8..33c491b24d 100644 --- a/ReShadeFX.vcxproj +++ b/ReShadeFX.vcxproj @@ -21,7 +21,7 @@ {D1C2099B-BEC7-4993-8947-01D4A1F7EAE2} Win32Proj - 10.0.17763.0 + 10.0.19041.0 10.0 ReShade FX diff --git a/ReShadeFXC.vcxproj b/ReShadeFXC.vcxproj index 068f0eec36..c3336697b2 100644 --- a/ReShadeFXC.vcxproj +++ b/ReShadeFXC.vcxproj @@ -21,7 +21,7 @@ {65640687-0740-4681-B018-17DBF33E061C} Win32Proj - 10.0.17763.0 + 10.0.19041.0 10.0 FXC diff --git a/ReShadeInject.vcxproj b/ReShadeInject.vcxproj index 4629b648bc..69efbbb671 100644 --- a/ReShadeInject.vcxproj +++ b/ReShadeInject.vcxproj @@ -21,7 +21,7 @@ {D388A856-4100-49AB-8FAF-62D63F8AC155} Win32Proj - 10.0.17763.0 + 10.0.19041.0 10.0 Injector diff --git a/deps/ImGui.vcxproj b/deps/ImGui.vcxproj index 33fe23d328..fbba692529 100644 --- a/deps/ImGui.vcxproj +++ b/deps/ImGui.vcxproj @@ -20,7 +20,7 @@ {9A62233B-0B70-4B48-91E8-35AA666BC32E} - 10.0.17763.0 + 10.0.19041.0 10.0 diff --git a/deps/MinHook.vcxproj b/deps/MinHook.vcxproj index 8c9c80e7e9..6376a72945 100644 --- a/deps/MinHook.vcxproj +++ b/deps/MinHook.vcxproj @@ -20,7 +20,7 @@ {783FEDFB-5124-4F8C-87BC-70AA8490266B} - 10.0.17763.0 + 10.0.19041.0 10.0 diff --git a/deps/fpng.vcxproj b/deps/fpng.vcxproj index e164db5096..d80db0839e 100644 --- a/deps/fpng.vcxproj +++ b/deps/fpng.vcxproj @@ -20,7 +20,7 @@ {79F676AF-1A25-49BB-9549-E533D162FB0A} - 10.0.17763.0 + 10.0.19041.0 10.0 diff --git a/deps/glad.vcxproj b/deps/glad.vcxproj index 2a16e5591a..792c3957a1 100644 --- a/deps/glad.vcxproj +++ b/deps/glad.vcxproj @@ -20,7 +20,7 @@ {09C0D610-9B82-40D8-B37E-0D26E3BFF77F} - 10.0.17763.0 + 10.0.19041.0 10.0 diff --git a/deps/jxl_simple_lossless.vcxproj b/deps/jxl_simple_lossless.vcxproj index 96efb3cdfb..c6bf50bb60 100644 --- a/deps/jxl_simple_lossless.vcxproj +++ b/deps/jxl_simple_lossless.vcxproj @@ -20,7 +20,7 @@ {54216c95-7b51-46d3-ab11-4b341e76a774} - 10.0.17763.0 + 10.0.19041.0 10.0 @@ -86,7 +86,9 @@ - + + intrin.h + diff --git a/deps/stb.vcxproj b/deps/stb.vcxproj index 42c3cdbc99..b062cdae65 100644 --- a/deps/stb.vcxproj +++ b/deps/stb.vcxproj @@ -20,7 +20,7 @@ {723BDEF8-4A39-4961-BDAB-54074012FF47} - 10.0.17763.0 + 10.0.19041.0 10.0 diff --git a/deps/utfcpp b/deps/utfcpp index 63d64de49f..819011bb01 160000 --- a/deps/utfcpp +++ b/deps/utfcpp @@ -1 +1 @@ -Subproject commit 63d64de49fd6b829f7c8694df5ab2ee625cb7134 +Subproject commit 819011bb01628fe1aa2f1da9f2c842a48fd5680b diff --git a/examples/04-api_trace/api_trace_addon.cpp b/examples/04-api_trace/api_trace_addon.cpp index eb653f1081..434600894a 100644 --- a/examples/04-api_trace/api_trace_addon.cpp +++ b/examples/04-api_trace/api_trace_addon.cpp @@ -585,7 +585,7 @@ static void on_push_descriptors(command_list *, shader_stage stages, pipeline_la reshade::log::message(reshade::log::level::info, s.str().c_str()); } -static void on_bind_descriptor_tables(command_list *, shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables) +static void on_bind_descriptor_tables(command_list *, shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) { if (!s_do_capture) return; diff --git a/examples/09-depth/generic_depth_addon.cpp b/examples/09-depth/generic_depth_addon.cpp index 952164296a..5e3d4e3d7a 100644 --- a/examples/09-depth/generic_depth_addon.cpp +++ b/examples/09-depth/generic_depth_addon.cpp @@ -1363,7 +1363,7 @@ static void draw_settings_overlay(effect_runtime *runtime) clear_stats.clear_op == clear_op::fullscreen_draw ? " Fullscreen draw call" : ""); } - if (sorted_item_list.size() == 1 && !is_d3d12_or_vulkan) + if (!is_d3d12_or_vulkan) { if (bool value = (depth_stencil_backup->force_clear_index == std::numeric_limits::max()); ImGui::Checkbox(" Choose last clear operation with high number of draw calls", &value)) diff --git a/examples/10-texture_overlay/texture_overlay_addon.cpp b/examples/10-texture_overlay/texture_overlay_addon.cpp index 5b7d05097c..e6ff8a3f43 100644 --- a/examples/10-texture_overlay/texture_overlay_addon.cpp +++ b/examples/10-texture_overlay/texture_overlay_addon.cpp @@ -200,7 +200,7 @@ static void on_push_descriptors(command_list *cmd_list, shader_stage stages, pip } } } -static void on_bind_descriptor_tables(command_list *cmd_list, shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables) +static void on_bind_descriptor_tables(command_list *cmd_list, shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) { if ((stages & shader_stage::pixel) != shader_stage::pixel) return; diff --git a/examples/13-effects_during_frame/effects_during_frame_addon.cpp b/examples/13-effects_during_frame/effects_during_frame_addon.cpp index 5218b52020..48697a72fb 100644 --- a/examples/13-effects_during_frame/effects_during_frame_addon.cpp +++ b/examples/13-effects_during_frame/effects_during_frame_addon.cpp @@ -82,7 +82,7 @@ static bool on_end_render_pass(command_list *cmd_list) const resource_desc render_target_desc = device->get_resource_desc(device->get_resource_from_view(cmd_data.current_main_rtv)); if (render_target_desc.texture.width != width || render_target_desc.texture.height != height) - return; + return false; } // Render post-processing effects when a specific render pass is found (instead of at the end of the frame) diff --git a/examples/utils/state_tracking.cpp b/examples/utils/state_tracking.cpp index 604f2add1c..a22f51653f 100644 --- a/examples/utils/state_tracking.cpp +++ b/examples/utils/state_tracking.cpp @@ -124,7 +124,7 @@ static void on_bind_scissor_rects(command_list *cmd_list, uint32_t first, uint32 state.scissor_rects[i + first] = rects[i]; } -static void on_bind_descriptor_tables(command_list *cmd_list, shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables) +static void on_bind_descriptor_tables(command_list *cmd_list, shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) { auto &state = cmd_list->get_private_data()->descriptor_tables[stages]; diff --git a/include/reshade.hpp b/include/reshade.hpp index fa2d57ccaa..f596db33ef 100644 --- a/include/reshade.hpp +++ b/include/reshade.hpp @@ -370,7 +370,7 @@ namespace reshade } /// - /// Creates a new effect runtime for an existing swapchain, for when it was not already hooked by ReShade (e.g. because the RESHADE_DISABLE_GRAPHICS_HOOK environment variable is set). + /// Creates a new effect runtime for an existing swap chain, for when it was not already hooked by ReShade (e.g. because the RESHADE_DISABLE_GRAPHICS_HOOK environment variable is set). /// /// Underlying graphics API used. /// 'IDirect3DDevice9', 'ID3D10Device', 'ID3D11Device', 'ID3D12Device', 'HGLRC' or 'VkDevice', depending on the graphics API. diff --git a/include/reshade_api_device.hpp b/include/reshade_api_device.hpp index a7cc2260cb..4f65ddcf19 100644 --- a/include/reshade_api_device.hpp +++ b/include/reshade_api_device.hpp @@ -803,7 +803,7 @@ namespace reshade::api /// Index of the first pipeline parameter that describes the first descriptor table to bind (root parameter index in D3D12, descriptor set index in Vulkan). /// Number of descriptor tables to bind. /// Pointer to the first element of an array of descriptor tables to bind. - virtual void bind_descriptor_tables(shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables) = 0; + virtual void bind_descriptor_tables(shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables) { bind_descriptor_tables2(stages, layout, first, count, tables, 0, nullptr); } /// /// Binds an index buffer to the input-assembler stage. @@ -1177,6 +1177,18 @@ namespace reshade::api /// Optional pointer to a depth-stencil description, or to bind none. /// Additional parameters of the render pass. virtual void begin_render_pass2(uint32_t count, const render_pass_render_target_desc *rts, const render_pass_depth_stencil_desc *ds, render_pass_flags flags) = 0; + + /// + /// Binds an array of descriptor tables. + /// + /// Shader stages that will use the descriptors. + /// Pipeline layout that describes the descriptors. + /// Index of the first pipeline parameter that describes the first descriptor table to bind (root parameter index in D3D12, descriptor set index in Vulkan). + /// Number of descriptor tables to bind. + /// Pointer to the first element of an array of descriptor tables to bind. + /// Number of dynamic offsets. + /// Pointer to the first element of an array of dynamic offsets for any descriptors of type or . + virtual void bind_descriptor_tables2(shader_stage stages, pipeline_layout layout, uint32_t first, uint32_t count, const descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) = 0; }; /// diff --git a/include/reshade_api_pipeline.hpp b/include/reshade_api_pipeline.hpp index dae8808ab7..353db522be 100644 --- a/include/reshade_api_pipeline.hpp +++ b/include/reshade_api_pipeline.hpp @@ -111,10 +111,12 @@ namespace reshade::api /// Descriptors are an array of . /// constant_buffer = 6, + constant_buffer_with_dynamic_offset = 8, /// /// Descriptors are an array of . /// shader_storage_buffer = 7, + shader_storage_buffer_with_dynamic_offset = 9, /// /// Descriptors are an array of . /// @@ -147,8 +149,8 @@ namespace reshade::api push_descriptors_with_ranges = 3, push_descriptors_with_ranges_and_flags = 5, - descriptor_table_with_static_samplers [[deprecated]] = descriptor_table_with_flags, - push_descriptors_with_static_samplers [[deprecated]] = push_descriptors_with_ranges_and_flags, + descriptor_table_with_static_samplers [[deprecated("use 'pipeline_layout_param_type::descriptor_table_with_flags' instead")]] = descriptor_table_with_flags, + push_descriptors_with_static_samplers [[deprecated("use 'pipeline_layout_param_type::push_descriptors_with_ranges_and_flags' instead")]] = push_descriptors_with_ranges_and_flags, }; /// @@ -605,6 +607,7 @@ namespace reshade::api /// Stride of the entire vertex (this has to be consistent for all elements per vertex buffer binding). /// Set to zero in case this is unknown. /// + /// uint32_t stride = 0; /// /// Number of instances to draw using the same per-instance data before advancing by one element. @@ -1301,6 +1304,7 @@ namespace reshade::api alpha_func = 25, srgb_write_enable = 194, primitive_topology = 1000, + input_element_stride = 1009, sample_mask = 162, // Blend state diff --git a/include/reshade_api_resource.hpp b/include/reshade_api_resource.hpp index 965a2a680d..9e2b37e1f8 100644 --- a/include/reshade_api_resource.hpp +++ b/include/reshade_api_resource.hpp @@ -190,10 +190,10 @@ namespace reshade::api /// gpu_upload = 6, - gpu_only [[deprecated]] = default_, - cpu_to_gpu [[deprecated]] = upload, - gpu_to_cpu [[deprecated]] = readback, - cpu_only [[deprecated]] = scratch, + gpu_only [[deprecated("use 'memory_heap::default_' instead")]] = default_, + cpu_to_gpu [[deprecated("use 'memory_heap::upload' instead")]] = upload, + gpu_to_cpu [[deprecated("use 'memory_heap::readback' instead")]] = readback, + cpu_only [[deprecated("use 'memory_heap::scratch' instead")]] = scratch, }; /// diff --git a/include/reshade_events.hpp b/include/reshade_events.hpp index 70f5c3b52c..80d68c1c37 100644 --- a/include/reshade_events.hpp +++ b/include/reshade_events.hpp @@ -403,6 +403,9 @@ namespace reshade /// /// Callback function signature: void (api::device *device, api::resource resource) /// + /// + /// This may be called from within other API calls, e.g. , so be careful with synchronization primitives in the callback. + /// destroy_resource, /// @@ -496,6 +499,7 @@ namespace reshade /// /// /// Is not called in D3D12 (since resource views are descriptor handles instead of objects there). + /// This may be called from within other API calls, e.g. , so be careful with synchronization primitives in the callback. /// destroy_resource_view, @@ -753,6 +757,7 @@ namespace reshade /// /// /// Is not called in D3D9. + /// This may be called from within other API calls, e.g. , so be careful with synchronization primitives in the callback. /// destroy_pipeline, @@ -1101,7 +1106,7 @@ namespace reshade /// ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable /// vkCmdBindDescriptorSets /// - /// Callback function signature: void (api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) + /// Callback function signature: void (api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) /// bind_descriptor_tables, @@ -1890,7 +1895,7 @@ namespace reshade RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::bind_scissor_rects, void, api::command_list *cmd_list, uint32_t first, uint32_t count, const api::rect *rects); RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::push_constants, void, api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values); RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::push_descriptors, void, api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update); - RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::bind_descriptor_tables, void, api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables); + RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::bind_descriptor_tables, void, api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets); RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::bind_index_buffer, void, api::command_list *cmd_list, api::resource buffer, uint64_t offset, uint32_t index_size); RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::bind_vertex_buffers, void, api::command_list *cmd_list, uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides); RESHADE_DEFINE_ADDON_EVENT_TRAITS(addon_event::bind_stream_output_buffers, void, api::command_list *cmd_list, uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint64_t *max_sizes, const api::resource *counter_buffers, const uint64_t *counter_offsets); diff --git a/res/lang_ar-SA.rc2 b/res/lang_ar-SA.rc2 index 0ad267669c..1d48013531 100644 --- a/res/lang_ar-SA.rc2 +++ b/res/lang_ar-SA.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "ﺔﻣﺎﻌﻟﺍ ﻖﺒﺴﻤﻟﺍ ﺞﻟﺎﻌﻤﻟﺍ ﺕﺎﻔﻳﺮﻌﺗ ﻞﻳﺪﻌﺗ" 2314 "ﻡﺎﻋ" 38344 "ﻲﻟﺎﺤﻟﺍ ﺐﻟﺎﻘﻟﺍ" +19882 "الاسم" +22129 "القيمة" 10646 "؟'%s' ﻖﺒﺴﻤﻟﺍ ﺞﻟﺎﻌﻤﻟﺍ ﻒﻳﺮﻌﺗ ﺔﻟﺍﺯﺇ ًﺎﻘﺣ ﺪﻳﺮﺗ ﻞﻫ" 63179 "ﻖﻴﺒﻄﺗ" 9813 "ﻲﺿﺍﺮﺘﻓﻼﻟ ﻞﻜﻟﺍ ﻂﺒﺿ ﺓﺩﺎﻋﺇ" diff --git a/res/lang_bg-BG.rc2 b/res/lang_bg-BG.rc2 index 4b73b9dfaf..872cf891ed 100644 --- a/res/lang_bg-BG.rc2 +++ b/res/lang_bg-BG.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Редактирай глобалните дефиниции за предпроцесора" 2314 "Глобален" 38344 "Текущ preset" +19882 "Име" +22129 "Стойност" 10646 "Наистина ли искате да премахнете дефиницията за предпроцесора '%s'?" 63179 "Прилагайте" 9813 "Нулиране на всички към стойностите им по подразбиране" diff --git a/res/lang_de-DE.rc2 b/res/lang_de-DE.rc2 index a5a2e653c8..b3b6778664 100644 --- a/res/lang_de-DE.rc2 +++ b/res/lang_de-DE.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Globale Präprozessordefinitionen bearbeiten" 2314 "Global" 38344 "Aktuelles Preset" +19882 "Name" +22129 "Wert" 10646 "Möchtest du die Präprozessordefinition '%s' wirklich entfernen?" 63179 "Anwenden" 9813 "Alle zurücksetzen" diff --git a/res/lang_en-US.rc2 b/res/lang_en-US.rc2 index a08e4ee807..f1a1172b2a 100644 --- a/res/lang_en-US.rc2 +++ b/res/lang_en-US.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Edit global preprocessor definitions" 2314 "Global" 38344 "Current Preset" +19882 "Name" +22129 "Value" 10646 "Do you really want to remove the preprocessor definition '%s'?" 63179 "Apply" 9813 "Reset all to default" diff --git a/res/lang_es-ES.rc2 b/res/lang_es-ES.rc2 index f8bc0f48d5..8fd346cc81 100644 --- a/res/lang_es-ES.rc2 +++ b/res/lang_es-ES.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Editar definiciones globales del preprocesador" 2314 "Global" 38344 "Preset Actual" +19882 "Nombre" +22129 "Valor" 10646 "¿Remover la definición del preprocesador '%s'?" 63179 "Aplicar" 9813 "Resetear todo" diff --git a/res/lang_fr-FR.rc2 b/res/lang_fr-FR.rc2 index 69feac2bc4..052887a1cc 100644 --- a/res/lang_fr-FR.rc2 +++ b/res/lang_fr-FR.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Éditer les définitions des pré-processeurs globaux" 2314 "Global" 38344 "Configuration actuelle" +19882 "Nom" +22129 "Valeur" 10646 "Êtes vous certain de vouloir supprimer la définition du pré-processeur '%s'?" 63179 "Appliquer" 9813 "Réinitialiser aux valeurs par défaut" diff --git a/res/lang_ja-JP.rc2 b/res/lang_ja-JP.rc2 index 8f3a2380ad..a49d4a4240 100644 --- a/res/lang_ja-JP.rc2 +++ b/res/lang_ja-JP.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "プリプロセッサの定義を編集" 2314 "共通" 38344 "プリセット" +19882 "名前" +22129 "値" 10646 "プリプロセッサの定義'%s'を削除します。" 63179 "適用する" 9813 "すべてを初期値にリセット" diff --git a/res/lang_ko-KR.rc2 b/res/lang_ko-KR.rc2 index 3f64b04b62..c9a8231e41 100644 --- a/res/lang_ko-KR.rc2 +++ b/res/lang_ko-KR.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "공통 프리프로세서 정의 편집" 2314 "공통" 38344 "현재 사전 설정" +19882 "이름" +22129 "값" 10646 "프리프로세서 정의 '%s'을(를) 제거할까요?" 63179 "신청하기" 9813 "모두 기본값으로 재설정" diff --git a/res/lang_pl-PL.rc2 b/res/lang_pl-PL.rc2 index 16643e3360..dec19a375a 100644 --- a/res/lang_pl-PL.rc2 +++ b/res/lang_pl-PL.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Edytuj globalne definicje preprocesora" 2314 "Globalne" 38344 "Obecny profil" +19882 "Nazwa" +22129 "Wartość" 10646 "Czy na pewno chcesz usunąć definicję preprocesora '%s'?" 63179 "Zatwierdź" 9813 "Zresetuj wszystko do wartości domyślnych" diff --git a/res/lang_pt-BR.rc2 b/res/lang_pt-BR.rc2 index 421c5b5d57..95a15ec025 100644 --- a/res/lang_pt-BR.rc2 +++ b/res/lang_pt-BR.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Editar definições globais do pré-processador" 2314 "Global" 38344 "Preset atual" +19882 "Nome" +22129 "Valor" 10646 "Você realmente deseja remover a definição do pré-processador '%s'?" 63179 "Aplicar" 9813 "Resetar tudo para o padrão" diff --git a/res/lang_ru-RU.rc2 b/res/lang_ru-RU.rc2 index 42489eff57..9de80c5983 100644 --- a/res/lang_ru-RU.rc2 +++ b/res/lang_ru-RU.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Редактирование глобальных определений препроцессора" 2314 "Глобальное" 38344 "Текущий пресет" +19882 "Имя" +22129 "Значение" 10646 "Вы действительно хотите удалить определение препроцессора '%s'?" 63179 "Применить" 9813 "Сброс всего на стандарт" diff --git a/res/lang_sl-SI.rc2 b/res/lang_sl-SI.rc2 index 79bd65544a..82a749a916 100644 --- a/res/lang_sl-SI.rc2 +++ b/res/lang_sl-SI.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Uredi globalne predprocesorske definicije" 2314 "Globalno" 38344 "Trenutna prednastavitev" +19882 "Ime" +22129 "Vrednost" 10646 "Ali res želite odstraniti predprocesorsko definicijo '%s'?" 63179 "Uporabi" 9813 "Ponastavi vse na privzeto" diff --git a/res/lang_th-TH.rc2 b/res/lang_th-TH.rc2 index fd53977a38..8f4db0be60 100644 --- a/res/lang_th-TH.rc2 +++ b/res/lang_th-TH.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "แก้ไขคำนิยาม preprocessor ทั่วไป" 2314 "ทั่วไป" 38344 "พรีเซ็ตปัจจุบัน" +19882 "ชื่อ" +22129 "ค่า" 10646 "คุณแน่ใจหรือว่าต้องการลบคำนิยาม preprocessor '%s'?" 63179 "ใช้" 9813 "รีเซ็ตทั้งหมดเป็นค่าเริ่มต้น" diff --git a/res/lang_tr-TR.rc2 b/res/lang_tr-TR.rc2 index 9007537f6d..71dfa702d1 100644 --- a/res/lang_tr-TR.rc2 +++ b/res/lang_tr-TR.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "Genel önişlemci tanımlarını düzenle" 2314 "Genel" 38344 "Geçerli Ön Ayar" +19882 "Ad" +22129 "Değer" 10646 "'%s' önişlemci tanımını gerçekten kaldırmak istiyor musunuz?" 63179 "Uygula" 9813 "Tümünü varsayılanlara sıfırla" diff --git a/res/lang_zh-CN.rc2 b/res/lang_zh-CN.rc2 index 35759aa5da..9e2100dac5 100644 --- a/res/lang_zh-CN.rc2 +++ b/res/lang_zh-CN.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "编辑全局/预设预处理器定义" 2314 "全局" 38344 "当前预设" +19882 "名称" +22129 "值" 10646 "真的要移除全局预处理器 '%s' 吗?" 63179 "应用" 9813 "全部重置为默认值" diff --git a/res/lang_zh-HK.rc2 b/res/lang_zh-HK.rc2 index b8c8e03c80..7bff1d0852 100644 --- a/res/lang_zh-HK.rc2 +++ b/res/lang_zh-HK.rc2 @@ -170,6 +170,8 @@ BEGIN 17289 "編輯全局/預設預處理器定義" 2314 "全局" 38344 "當前預設" +19882 "名稱" +22129 "值" 10646 "真的要移除全域預處理器 '%s' 嗎?" 63179 "應用" 9813 "全部重置爲默認值" diff --git a/setup/MainWindow.xaml.cs b/setup/MainWindow.xaml.cs index dc74706efd..9ce8d3ddba 100644 --- a/setup/MainWindow.xaml.cs +++ b/setup/MainWindow.xaml.cs @@ -684,6 +684,16 @@ void InstallStep_AnalyzeExecutable() return; } + if (peInfo.StackSize < 1024 * 1024) + { + UpdateStatus("Waiting for user confirmation ..."); + + Dispatcher.Invoke(() => + { + MessageBox.Show(this, "The target application uses a small default stack size.\nIn order to use ReShade without crashing you'll have to patch the executable to increase the stack size from " + peInfo.StackSize + " bytes to at least 1 MB.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); + }); + } + if (compatibilityIni != null && compatibilityIni.HasValue(executableName, "RenderApi")) { if (compatibilityIni.HasValue(executableName, "InstallTarget")) diff --git a/setup/Utilities/PEInfo.cs b/setup/Utilities/PEInfo.cs index 4cf3846be7..7dce4a2534 100644 --- a/setup/Utilities/PEInfo.cs +++ b/setup/Utilities/PEInfo.cs @@ -39,11 +39,17 @@ struct LOADED_IMAGE public UInt32 SizeOfImage; } - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Explicit)] struct IMAGE_NT_HEADERS { + [FieldOffset(0)] public UInt32 Signature; + [FieldOffset(4)] public IMAGE_FILE_HEADER FileHeader; + [FieldOffset(24)] + public IMAGE_OPTIONAL_HEADER32 OptionalHeader32; + [FieldOffset(24)] + public IMAGE_OPTIONAL_HEADER64 OptionalHeader64; } [StructLayout(LayoutKind.Sequential)] @@ -58,6 +64,74 @@ struct IMAGE_FILE_HEADER public UInt16 Characteristics; } + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_OPTIONAL_HEADER32 + { + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public UInt32 BaseOfData; + public UInt32 ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public UInt32 SizeOfStackReserve; + public UInt32 SizeOfStackCommit; + public UInt32 SizeOfHeapReserve; + public UInt32 SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + } + [StructLayout(LayoutKind.Sequential)] + struct IMAGE_OPTIONAL_HEADER64 + { + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public UInt64 ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public UInt64 SizeOfStackReserve; + public UInt64 SizeOfStackCommit; + public UInt64 SizeOfHeapReserve; + public UInt64 SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + } + [StructLayout(LayoutKind.Explicit)] struct IMAGE_IMPORT_DESCRIPTOR { @@ -131,7 +205,9 @@ public PEInfo(string path) } } - Type = ((IMAGE_NT_HEADERS*)image.FileHeader)->FileHeader.Machine; + var headers = (IMAGE_NT_HEADERS*)image.FileHeader; + Type = headers->FileHeader.Machine; + StackSize = Type == BinaryType.IMAGE_FILE_MACHINE_AMD64 ? headers->OptionalHeader64.SizeOfStackReserve : (ulong)headers->OptionalHeader32.SizeOfStackReserve; UnMapAndLoad(ref image); } @@ -149,6 +225,11 @@ public IEnumerable Modules get; } + public ulong StackSize + { + get; + } + public static string ReadResourceString(string path, ushort id) { string result = null; diff --git a/source/addon_manager.hpp b/source/addon_manager.hpp index 00d359fc4c..2a9ab7e489 100644 --- a/source/addon_manager.hpp +++ b/source/addon_manager.hpp @@ -174,7 +174,7 @@ namespace reshade "Event that is disabled with limited add-on support was used!"); if constexpr ( - ev != addon_event::create_resource_view) // This is needed by the Generic Depth add-on so that view creation succeeds for resources where the format was overriden + ev != addon_event::create_resource_view) // This is needed by the Generic Depth add-on so that view creation succeeds for resources where the format was overridden if (!addon_enabled) return false; #endif diff --git a/source/d3d10/d3d10_device.cpp b/source/d3d10/d3d10_device.cpp index e0b998662d..0d0d39c91b 100644 --- a/source/d3d10/d3d10_device.cpp +++ b/source/d3d10/d3d10_device.cpp @@ -10,6 +10,7 @@ #include "com_utils.hpp" #include "hook_manager.hpp" #include "addon_manager.hpp" +#include // _ReturnAddress using reshade::d3d10::to_handle; @@ -1162,12 +1163,15 @@ HRESULT STDMETHODCALLTYPE D3D10Device::CreateInputLayout(const D3D10_INPUT_ELEME for (UINT i = 0; i < NumElements; ++i) desc.push_back(reshade::d3d10::convert_input_element(pInputElementDescs[i])); + reshade::api::dynamic_state dynamic_states[] = { reshade::api::dynamic_state::input_element_stride }; + reshade::api::shader_desc signature_desc = {}; signature_desc.code = pShaderBytecodeWithInputSignature; signature_desc.code_size = BytecodeLength; const reshade::api::pipeline_subobject subobjects[] = { { reshade::api::pipeline_subobject_type::input_layout, static_cast(desc.size()), desc.data() }, + { reshade::api::pipeline_subobject_type::dynamic_pipeline_states, static_cast(std::size(dynamic_states)), dynamic_states }, { reshade::api::pipeline_subobject_type::vertex_shader, 1, &signature_desc } }; diff --git a/source/d3d10/d3d10_impl_command_list.cpp b/source/d3d10/d3d10_impl_command_list.cpp index bf5d313c1c..473a9576a5 100644 --- a/source/d3d10/d3d10_impl_command_list.cpp +++ b/source/d3d10/d3d10_impl_command_list.cpp @@ -420,7 +420,7 @@ void reshade::d3d10::device_impl::push_descriptors(api::shader_stage stages, api break; } } -void reshade::d3d10::device_impl::bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) +void reshade::d3d10::device_impl::bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t, const uint32_t *) { for (uint32_t i = 0; i < count; ++i) { diff --git a/source/d3d10/d3d10_impl_device.cpp b/source/d3d10/d3d10_impl_device.cpp index 431d3b8eed..deef0bf826 100644 --- a/source/d3d10/d3d10_impl_device.cpp +++ b/source/d3d10/d3d10_impl_device.cpp @@ -874,6 +874,7 @@ bool reshade::d3d10::device_impl::create_pipeline(api::pipeline_layout, uint32_t for (uint32_t k = 0; k < subobjects[i].count; ++k) if (const auto state = static_cast(subobjects[i].data)[k]; state != api::dynamic_state::primitive_topology && + state != api::dynamic_state::input_element_stride && state != api::dynamic_state::blend_constant && state != api::dynamic_state::sample_mask && state != api::dynamic_state::front_stencil_reference_value && diff --git a/source/d3d10/d3d10_impl_device.hpp b/source/d3d10/d3d10_impl_device.hpp index e082457ad3..2cf32a410f 100644 --- a/source/d3d10/d3d10_impl_device.hpp +++ b/source/d3d10/d3d10_impl_device.hpp @@ -119,7 +119,7 @@ namespace reshade::d3d10 void push_constants(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values) final; void push_descriptors(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update) final; - void bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) final; + void bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) final; void bind_index_buffer(api::resource buffer, uint64_t offset, uint32_t index_size) final; void bind_vertex_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides) final; diff --git a/source/d3d11/d3d11_device.cpp b/source/d3d11/d3d11_device.cpp index c623ca48e0..7969a02d8e 100644 --- a/source/d3d11/d3d11_device.cpp +++ b/source/d3d11/d3d11_device.cpp @@ -12,6 +12,7 @@ #include "com_utils.hpp" #include "hook_manager.hpp" #include "addon_manager.hpp" +#include // _ReturnAddress using reshade::d3d11::to_handle; @@ -626,12 +627,15 @@ HRESULT STDMETHODCALLTYPE D3D11Device::CreateInputLayout(const D3D11_INPUT_ELEME for (UINT i = 0; i < NumElements; ++i) desc.push_back(reshade::d3d11::convert_input_element(pInputElementDescs[i])); + reshade::api::dynamic_state dynamic_states[] = { reshade::api::dynamic_state::input_element_stride }; + reshade::api::shader_desc signature_desc = {}; signature_desc.code = pShaderBytecodeWithInputSignature; signature_desc.code_size = BytecodeLength; const reshade::api::pipeline_subobject subobjects[] = { { reshade::api::pipeline_subobject_type::input_layout, static_cast(desc.size()), desc.data() }, + { reshade::api::pipeline_subobject_type::dynamic_pipeline_states, static_cast(std::size(dynamic_states)), dynamic_states }, { reshade::api::pipeline_subobject_type::vertex_shader, 1, &signature_desc } }; diff --git a/source/d3d11/d3d11_impl_command_list.cpp b/source/d3d11/d3d11_impl_command_list.cpp index e5eb42fc10..096a73c507 100644 --- a/source/d3d11/d3d11_impl_command_list.cpp +++ b/source/d3d11/d3d11_impl_command_list.cpp @@ -592,7 +592,7 @@ void reshade::d3d11::device_context_impl::push_descriptors(api::shader_stage sta break; } } -void reshade::d3d11::device_context_impl::bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) +void reshade::d3d11::device_context_impl::bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t, const uint32_t *) { for (uint32_t i = 0; i < count; ++i) { @@ -813,28 +813,28 @@ void reshade::d3d11::device_context_impl::query_acceleration_structures(uint32_t assert(false); } -void reshade::d3d11::device_context_impl::update_buffer_region(const void *data, api::resource dest, uint64_t dest_offset, uint64_t size) +void reshade::d3d11::device_context_impl::update_buffer_region(const void *data, api::resource dst, uint64_t dst_offset, uint64_t size) { - assert(dest != 0); + assert(dst != 0); if (UINT64_MAX == size) { D3D11_BUFFER_DESC desc; - reinterpret_cast(dest.handle)->GetDesc(&desc); + reinterpret_cast(dst.handle)->GetDesc(&desc); size = desc.ByteWidth; } - assert(dest_offset <= std::numeric_limits::max() && size <= std::numeric_limits::max()); + assert(dst_offset <= std::numeric_limits::max() && size <= std::numeric_limits::max()); - const D3D11_BOX box = { static_cast(dest_offset), 0, 0, static_cast(dest_offset + size), 1, 1 }; + const D3D11_BOX box = { static_cast(dst_offset), 0, 0, static_cast(dst_offset + size), 1, 1 }; - _orig->UpdateSubresource(reinterpret_cast(dest.handle), 0, dest_offset != 0 ? &box : nullptr, data, static_cast(size), 0); + _orig->UpdateSubresource(reinterpret_cast(dst.handle), 0, dst_offset != 0 ? &box : nullptr, data, static_cast(size), 0); } -void reshade::d3d11::device_context_impl::update_texture_region(const api::subresource_data &data, api::resource dest, uint32_t dest_subresource, const api::subresource_box *dest_box) +void reshade::d3d11::device_context_impl::update_texture_region(const api::subresource_data &data, api::resource dst, uint32_t dst_subresource, const api::subresource_box *dst_box) { - assert(dest != 0); + assert(dst != 0); - _orig->UpdateSubresource(reinterpret_cast(dest.handle), dest_subresource, reinterpret_cast(dest_box), data.data, data.row_pitch, data.slice_pitch); + _orig->UpdateSubresource(reinterpret_cast(dst.handle), dst_subresource, reinterpret_cast(dst_box), data.data, data.row_pitch, data.slice_pitch); } void reshade::d3d11::device_context_impl::begin_debug_event(const char *label, const float[4]) diff --git a/source/d3d11/d3d11_impl_device.cpp b/source/d3d11/d3d11_impl_device.cpp index 2dc551e30e..cb6f505e76 100644 --- a/source/d3d11/d3d11_impl_device.cpp +++ b/source/d3d11/d3d11_impl_device.cpp @@ -1121,6 +1121,7 @@ bool reshade::d3d11::device_impl::create_pipeline(api::pipeline_layout, uint32_t for (uint32_t k = 0; k < subobjects[i].count; ++k) if (const auto state = static_cast(subobjects[i].data)[k]; state != api::dynamic_state::primitive_topology && + state != api::dynamic_state::input_element_stride && state != api::dynamic_state::blend_constant && state != api::dynamic_state::sample_mask && state != api::dynamic_state::front_stencil_reference_value && diff --git a/source/d3d11/d3d11_impl_device_context.hpp b/source/d3d11/d3d11_impl_device_context.hpp index 5c7a6cc09f..a68e3ed3d6 100644 --- a/source/d3d11/d3d11_impl_device_context.hpp +++ b/source/d3d11/d3d11_impl_device_context.hpp @@ -29,7 +29,7 @@ namespace reshade::d3d11 void push_constants(api::shader_stage, api::pipeline_layout, uint32_t, uint32_t, uint32_t, const void *) final { assert(false); } void push_descriptors(api::shader_stage, api::pipeline_layout, uint32_t, const api::descriptor_table_update &) final { assert(false); } - void bind_descriptor_tables(api::shader_stage, api::pipeline_layout, uint32_t, uint32_t, const api::descriptor_table *) final { assert(false); } + void bind_descriptor_tables2(api::shader_stage, api::pipeline_layout, uint32_t, uint32_t, const api::descriptor_table *, uint32_t, const uint32_t *) final { assert(false); } void bind_index_buffer(api::resource, uint64_t, uint32_t) final { assert(false); } void bind_vertex_buffers(uint32_t, uint32_t, const api::resource *, const uint64_t *, const uint32_t *) final { assert(false); } @@ -111,7 +111,7 @@ namespace reshade::d3d11 void push_constants(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values) final; void push_descriptors(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update) final; - void bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) final; + void bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) final; void bind_index_buffer(api::resource buffer, uint64_t offset, uint32_t index_size) final; void bind_vertex_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides) final; diff --git a/source/d3d12/d3d12_command_list.cpp b/source/d3d12/d3d12_command_list.cpp index 8726653564..44f3d73460 100644 --- a/source/d3d12/d3d12_command_list.cpp +++ b/source/d3d12/d3d12_command_list.cpp @@ -211,7 +211,7 @@ void STDMETHODCALLTYPE D3D12GraphicsCommandList::ClearState(ID3D12PipelineState constexpr size_t max_null_objects = D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT * 2; void *const null_objects[max_null_objects] = {}; - reshade::invoke_addon_event(this, reshade::api::shader_stage::all, reshade::api::pipeline_layout {}, 0, 0, nullptr); + reshade::invoke_addon_event(this, reshade::api::shader_stage::all, reshade::api::pipeline_layout {}, 0, 0, nullptr, 0, nullptr); reshade::invoke_addon_event(this, reshade::api::resource {}, 0, 0); reshade::invoke_addon_event(this, 0, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT, reinterpret_cast(null_objects), reinterpret_cast(null_objects), reinterpret_cast(null_objects)); @@ -529,6 +529,7 @@ void STDMETHODCALLTYPE D3D12GraphicsCommandList::SetComputeRootSignature(ID3D12R reshade::api::shader_stage::all_compute | reshade::api::shader_stage::all_ray_tracing, to_handle(_current_root_signature[1]), 0, + 0, nullptr, 0, nullptr); #endif } @@ -544,6 +545,7 @@ void STDMETHODCALLTYPE D3D12GraphicsCommandList::SetGraphicsRootSignature(ID3D12 reshade::api::shader_stage::all_graphics, to_handle(_current_root_signature[0]), 0, + 0, nullptr, 0, nullptr); #endif } @@ -557,7 +559,8 @@ void STDMETHODCALLTYPE D3D12GraphicsCommandList::SetComputeRootDescriptorTable(U reshade::api::shader_stage::all_compute | reshade::api::shader_stage::all_ray_tracing, to_handle(_current_root_signature[1]), RootParameterIndex, - 1, reinterpret_cast(&BaseDescriptor)); + 1, reinterpret_cast(&BaseDescriptor), + 0, nullptr); #endif } void STDMETHODCALLTYPE D3D12GraphicsCommandList::SetGraphicsRootDescriptorTable(UINT RootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE BaseDescriptor) @@ -570,7 +573,8 @@ void STDMETHODCALLTYPE D3D12GraphicsCommandList::SetGraphicsRootDescriptorTable( reshade::api::shader_stage::all_graphics, to_handle(_current_root_signature[0]), RootParameterIndex, - 1, reinterpret_cast(&BaseDescriptor)); + 1, reinterpret_cast(&BaseDescriptor), + 0, nullptr); #endif } void STDMETHODCALLTYPE D3D12GraphicsCommandList::SetComputeRoot32BitConstant(UINT RootParameterIndex, UINT SrcData, UINT DestOffsetIn32BitValues) diff --git a/source/d3d12/d3d12_device.cpp b/source/d3d12/d3d12_device.cpp index 1f04f3ce76..fab80ad327 100644 --- a/source/d3d12/d3d12_device.cpp +++ b/source/d3d12/d3d12_device.cpp @@ -2798,6 +2798,7 @@ bool D3D12Device::invoke_create_and_init_pipeline_event(const D3D12_PIPELINE_STA std::vector dynamic_states = { reshade::api::dynamic_state::primitive_topology, + reshade::api::dynamic_state::input_element_stride, reshade::api::dynamic_state::blend_constant, reshade::api::dynamic_state::front_stencil_reference_value, reshade::api::dynamic_state::back_stencil_reference_value diff --git a/source/d3d12/d3d12_impl_command_list.cpp b/source/d3d12/d3d12_impl_command_list.cpp index 0dc921c409..b35d645a67 100644 --- a/source/d3d12/d3d12_impl_command_list.cpp +++ b/source/d3d12/d3d12_impl_command_list.cpp @@ -494,7 +494,7 @@ void reshade::d3d12::command_list_impl::push_descriptors(api::shader_stage stage _orig->SetGraphicsRootDescriptorTable(layout_param, base_handle_gpu); } } -void reshade::d3d12::command_list_impl::bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) +void reshade::d3d12::command_list_impl::bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) { assert(tables != nullptr || count == 0); diff --git a/source/d3d12/d3d12_impl_command_list.hpp b/source/d3d12/d3d12_impl_command_list.hpp index 4f0a44b1a5..c9b3fa8396 100644 --- a/source/d3d12/d3d12_impl_command_list.hpp +++ b/source/d3d12/d3d12_impl_command_list.hpp @@ -32,7 +32,7 @@ namespace reshade::d3d12 void push_constants(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values) final; void push_descriptors(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update) final; - void bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) final; + void bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) final; void bind_index_buffer(api::resource buffer, uint64_t offset, uint32_t index_size) final; void bind_vertex_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides) final; diff --git a/source/d3d12/d3d12_impl_device.cpp b/source/d3d12/d3d12_impl_device.cpp index 22520da700..b1bbfc0288 100644 --- a/source/d3d12/d3d12_impl_device.cpp +++ b/source/d3d12/d3d12_impl_device.cpp @@ -931,6 +931,7 @@ bool reshade::d3d12::device_impl::create_pipeline(api::pipeline_layout layout, u for (uint32_t k = 0; k < subobjects[i].count; ++k) if (const auto state = static_cast(subobjects[i].data)[k]; state != api::dynamic_state::primitive_topology && + state != api::dynamic_state::input_element_stride && state != api::dynamic_state::blend_constant && state != api::dynamic_state::front_stencil_reference_value && state != api::dynamic_state::back_stencil_reference_value && diff --git a/source/d3d12/d3d12_impl_type_convert.cpp b/source/d3d12/d3d12_impl_type_convert.cpp index 2336c5d75f..169113c5b5 100644 --- a/source/d3d12/d3d12_impl_type_convert.cpp +++ b/source/d3d12/d3d12_impl_type_convert.cpp @@ -5,7 +5,7 @@ #include "d3d12_impl_type_convert.hpp" #include -#include // std::copy_n, std::fill_n +#include // std::copy_n, std::fill_n, std::max auto reshade::d3d12::convert_format(api::format format) -> DXGI_FORMAT { @@ -54,6 +54,26 @@ auto reshade::d3d12::convert_color_space(DXGI_COLOR_SPACE_TYPE type) -> api::col } } +void reshade::d3d12::convert_subresource_box(const reshade::api::subresource_box *box, const D3D12_RESOURCE_DESC &desc, uint32_t subresource, UINT &width, UINT &height, UINT &depth) +{ + if (box != nullptr) + { + width = box->width(); + height = box->height(); + depth = box->depth(); + } + else + { + width = std::max(1u, static_cast(desc.Width) >> (subresource % desc.MipLevels)); + height = std::max(1u, desc.Height >> (subresource % desc.MipLevels)); + + if (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) + depth = std::max(1u, static_cast(desc.DepthOrArraySize) >> (subresource % desc.MipLevels)); + else + depth = 1; + } +} + auto reshade::d3d12::convert_access_to_usage(D3D12_BARRIER_ACCESS access) -> api::resource_usage { if (access == D3D12_BARRIER_ACCESS_COMMON) diff --git a/source/d3d12/d3d12_impl_type_convert.hpp b/source/d3d12/d3d12_impl_type_convert.hpp index 217894a29a..c9549e0186 100644 --- a/source/d3d12/d3d12_impl_type_convert.hpp +++ b/source/d3d12/d3d12_impl_type_convert.hpp @@ -48,25 +48,7 @@ namespace reshade::d3d12 auto convert_color_space(api::color_space type) -> DXGI_COLOR_SPACE_TYPE; auto convert_color_space(DXGI_COLOR_SPACE_TYPE type) -> api::color_space; - inline void convert_subresource_box(const reshade::api::subresource_box *box, const D3D12_RESOURCE_DESC &desc, uint32_t subresource, UINT &width, UINT &height, UINT &depth) - { - if (box != nullptr) - { - width = box->width(); - height = box->height(); - depth = box->depth(); - } - else - { - width = std::max(1u, static_cast(desc.Width) >> (subresource % desc.MipLevels)); - height = std::max(1u, desc.Height >> (subresource % desc.MipLevels)); - - if (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) - depth = std::max(1u, static_cast(desc.DepthOrArraySize) >> (subresource % desc.MipLevels)); - else - depth = 1; - } - } + void convert_subresource_box(const reshade::api::subresource_box *box, const D3D12_RESOURCE_DESC &desc, uint32_t subresource, UINT &width, UINT &height, UINT &depth); auto convert_access_to_usage(D3D12_BARRIER_ACCESS access) -> api::resource_usage; auto convert_barrier_layout_to_usage(D3D12_BARRIER_LAYOUT layout) -> api::resource_usage; diff --git a/source/d3d12/d3d12_pipeline_library.cpp b/source/d3d12/d3d12_pipeline_library.cpp index c48f15088c..83f16fba05 100644 --- a/source/d3d12/d3d12_pipeline_library.cpp +++ b/source/d3d12/d3d12_pipeline_library.cpp @@ -25,7 +25,7 @@ bool D3D12PipelineLibrary::check_and_upgrade_interface(REFIID riid) riid == __uuidof(ID3D12DeviceChild)) return true; - static const IID iid_lookup[] = { + static constexpr IID iid_lookup[] = { __uuidof(ID3D12PipelineLibrary), __uuidof(ID3D12PipelineLibrary1), }; diff --git a/source/d3d9/d3d9_device.cpp b/source/d3d9/d3d9_device.cpp index de38c46b8c..293edcb814 100644 --- a/source/d3d9/d3d9_device.cpp +++ b/source/d3d9/d3d9_device.cpp @@ -1902,8 +1902,11 @@ HRESULT STDMETHODCALLTYPE Direct3DDevice9::CreateVertexDeclaration(const D3DVERT for (const D3DVERTEXELEMENT9 *internal_element = pVertexElements; internal_element->Stream != 0xFF; ++internal_element) desc.push_back(reshade::d3d9::convert_input_element(*internal_element)); + reshade::api::dynamic_state dynamic_states[] = { reshade::api::dynamic_state::input_element_stride }; + const reshade::api::pipeline_subobject subobjects[] = { - { reshade::api::pipeline_subobject_type::input_layout, static_cast(desc.size()), desc.data() } + { reshade::api::pipeline_subobject_type::input_layout, static_cast(desc.size()), desc.data() }, + { reshade::api::pipeline_subobject_type::dynamic_pipeline_states, static_cast(std::size(dynamic_states)), dynamic_states } }; if (reshade::invoke_addon_event(this, _global_pipeline_layout, static_cast(std::size(subobjects)), subobjects)) diff --git a/source/d3d9/d3d9_impl_command_list.cpp b/source/d3d9/d3d9_impl_command_list.cpp index e7954ba9eb..52cfeabed4 100644 --- a/source/d3d9/d3d9_impl_command_list.cpp +++ b/source/d3d9/d3d9_impl_command_list.cpp @@ -378,7 +378,7 @@ void reshade::d3d9::device_impl::push_descriptors(api::shader_stage stages, api: } } } -void reshade::d3d9::device_impl::bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) +void reshade::d3d9::device_impl::bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t, const uint32_t *) { for (uint32_t i = 0; i < count; ++i) { diff --git a/source/d3d9/d3d9_impl_device.hpp b/source/d3d9/d3d9_impl_device.hpp index 4a52af8664..5ef8ed4296 100644 --- a/source/d3d9/d3d9_impl_device.hpp +++ b/source/d3d9/d3d9_impl_device.hpp @@ -112,7 +112,7 @@ namespace reshade::d3d9 void push_constants(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values) final; void push_descriptors(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update) final; - void bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) final; + void bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) final; void bind_index_buffer(api::resource buffer, [[maybe_unused]] uint64_t offset, [[maybe_unused]] uint32_t index_size) final; void bind_vertex_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides) final; diff --git a/source/d3d9/d3d9_impl_swapchain.cpp b/source/d3d9/d3d9_impl_swapchain.cpp index c4b90ea485..43a4da109d 100644 --- a/source/d3d9/d3d9_impl_swapchain.cpp +++ b/source/d3d9/d3d9_impl_swapchain.cpp @@ -20,7 +20,7 @@ reshade::api::device *reshade::d3d9::swapchain_impl::get_device() void *reshade::d3d9::swapchain_impl::get_hwnd() const { - // Destination window may be temporarily overriden by 'hDestWindowOverride' parameter during present call + // Destination window may be temporarily overridden by 'hDestWindowOverride' parameter during present call if (_hwnd != nullptr) return _hwnd; diff --git a/source/dxgi/dxgi_swapchain.cpp b/source/dxgi/dxgi_swapchain.cpp index bfdc28ed7d..ce7d6acb0b 100644 --- a/source/dxgi/dxgi_swapchain.cpp +++ b/source/dxgi/dxgi_swapchain.cpp @@ -404,7 +404,7 @@ HRESULT STDMETHODCALLTYPE DXGISwapChain::ResizeBuffers(UINT BufferCount, UINT Wi _orig->GetDesc(&desc); g_in_dxgi_runtime = was_in_dxgi_runtime; - // Restore default parameters to tho original values, rather than leaving them at the last values potentially overriden by an add-on + // Restore default parameters to tho original values, rather than leaving them at the last values potentially overridden by an add-on if (0 == BufferCount) BufferCount = _orig_desc.BufferCount; if (DXGI_FORMAT_UNKNOWN == NewFormat) @@ -775,7 +775,7 @@ HRESULT STDMETHODCALLTYPE DXGISwapChain::ResizeBuffers1(UINT BufferCount, UINT W _orig->GetFullscreenState(&fullscreen, nullptr); g_in_dxgi_runtime = was_in_dxgi_runtime; - // Restore default parameters to tho original values, rather than leaving them at the last values potentially overriden by an add-on + // Restore default parameters to tho original values, rather than leaving them at the last values potentially overridden by an add-on if (0 == BufferCount) BufferCount = _orig_desc.BufferCount; if (DXGI_FORMAT_UNKNOWN == NewFormat) diff --git a/source/effect_codegen_dxil.cpp b/source/effect_codegen_dxil.cpp index d2d3bb849a..eb6be90a26 100644 --- a/source/effect_codegen_dxil.cpp +++ b/source/effect_codegen_dxil.cpp @@ -67,7 +67,7 @@ class codegen_dxil final : public codegen_hlsl com_ptr result; - HRESULT hr = compiler->Compile(&hlsl_buffer, arguments, std::size(arguments), nullptr, IID_PPV_ARGS(&result)); + HRESULT hr = compiler->Compile(&hlsl_buffer, arguments, static_cast(std::size(arguments)), nullptr, IID_PPV_ARGS(&result)); if (result != nullptr) { result->GetStatus(&hr); diff --git a/source/effect_codegen_glsl.cpp b/source/effect_codegen_glsl.cpp index 4f90fde6aa..fc28b9feb7 100644 --- a/source/effect_codegen_glsl.cpp +++ b/source/effect_codegen_glsl.cpp @@ -700,7 +700,7 @@ class codegen_glsl : public codegen { assert(!name.empty()); - static const std::unordered_set s_reserverd_names = { + static const std::unordered_set s_reserved_names = { "common", "partition", "input", "output", "active", "filter", "superp", "invariant", "attribute", "varying", "buffer", "resource", "coherent", "readonly", "writeonly", "layout", "flat", "smooth", "lowp", "mediump", "highp", "precision", "patch", "subroutine", @@ -727,7 +727,7 @@ class codegen_glsl : public codegen }; // Escape reserved names so that they do not fail to compile - if (name.compare(0, 3, "gl_") == 0 || s_reserverd_names.count(name)) + if (name.compare(0, 3, "gl_") == 0 || s_reserved_names.count(name)) // Append an underscore at start instead of the end, since another one may get added in 'define_name' when there is a suffix // This is guaranteed to not clash with user defined names, since those starting with an underscore are filtered out in 'define_name' name = '_' + name; diff --git a/source/effect_lexer.cpp b/source/effect_lexer.cpp index 9c9db86e70..7d6069ebf7 100644 --- a/source/effect_lexer.cpp +++ b/source/effect_lexer.cpp @@ -5,6 +5,7 @@ #include "effect_lexer.hpp" #include +#include // std::from_chars #include #include // Used for static lookup tables @@ -96,7 +97,6 @@ static const std::unordered_map s_token_lookup = { { tokenid::int_literal, "integral literal" }, { tokenid::uint_literal, "integral literal" }, { tokenid::float_literal, "floating point literal" }, - { tokenid::double_literal, "floating point literal" }, { tokenid::string_literal, "string literal" }, { tokenid::namespace_, "namespace" }, { tokenid::struct_, "struct" }, @@ -576,7 +576,7 @@ reshadefx::token reshadefx::lexer::lex() tok.location = _cur_location; tok.offset = input_offset(); tok.length = 1; - tok.literal_as_double = 0; + tok.literal_as_uint = 0; tok.literal_as_string.clear(); assert(_cur <= _end); @@ -1064,7 +1064,7 @@ void reshadefx::lexer::parse_numeric_literal(token &tok) const // This routine handles both integer and floating point numbers auto *const begin = _cur, *end = _cur; int mantissa_size = 0, decimal_location = -1, radix = 10; - long long fraction = 0, exponent = 0; + long long mantissa = 0, exponent = 0; // If a literal starts with '0' it is either an octal or hexadecimal ('0x') value if (begin[0] == '0') @@ -1109,16 +1109,15 @@ void reshadefx::lexer::parse_numeric_literal(token &tok) const // Found a decimal character, as such convert current values if (radix == 8) { + mantissa = octal_to_decimal(mantissa); radix = 10; - fraction = octal_to_decimal(fraction); } decimal_location = mantissa_size; continue; } - fraction *= radix; - fraction += c; + mantissa = mantissa * radix + c; } // Ignore additional digits that cannot affect the value @@ -1129,7 +1128,6 @@ void reshadefx::lexer::parse_numeric_literal(token &tok) const if (decimal_location < 0) { tok.id = tokenid::int_literal; - decimal_location = mantissa_size; } else { @@ -1141,50 +1139,52 @@ void reshadefx::lexer::parse_numeric_literal(token &tok) const if (*end == 'E' || *end == 'e') { auto tmp = end + 1; - const bool negative = *tmp == '-'; - if (negative || *tmp == '+') + const bool exponent_negative = *tmp == '-'; + if (exponent_negative || *tmp == '+') tmp++; if (is_decimal_digit(*tmp)) { - end = tmp; - - tok.id = tokenid::float_literal; - do { - exponent *= 10; - exponent += (*end++) - '0'; - } while (is_decimal_digit(*end)); + exponent = exponent * 10 + (*tmp++) - '0'; + } while (is_decimal_digit(*tmp)); - if (negative) + if (exponent_negative) exponent = -exponent; + + end = tmp; + tok.id = tokenid::float_literal; } } // Various suffixes force specific literal types - if (*end == 'F' || *end == 'f') + if ((*end == 'U' || *end == 'u') && tok.id == tokenid::int_literal) // The 'u' suffix is only valid on integers and needs to be ignored otherwise { end++; // Consume the suffix - tok.id = tokenid::float_literal; + tok.id = tokenid::uint_literal; } - else if (*end == 'L' || *end == 'l') + else if (*end == 'F' || *end == 'f' || *end == 'L' || *end == 'l') { end++; // Consume the suffix - tok.id = tokenid::double_literal; + tok.id = tokenid::float_literal; } - else if (tok.id == tokenid::int_literal && (*end == 'U' || *end == 'u')) // The 'u' suffix is only valid on integers and needs to be ignored otherwise + + if (mantissa == 0) { - end++; // Consume the suffix - tok.id = tokenid::uint_literal; + tok.literal_as_uint = 0; } - - if (tok.id == tokenid::float_literal || tok.id == tokenid::double_literal) + else if (tok.id == tokenid::int_literal || tok.id == tokenid::uint_literal) { + // Limit the maximum value to what fits into our token structure + tok.literal_as_uint = static_cast(mantissa & 0xFFFFFFFF); + } + else + { +#if 0 exponent += decimal_location - mantissa_size; const bool exponent_negative = exponent < 0; - if (exponent_negative) exponent = -exponent; @@ -1210,15 +1210,10 @@ void reshadefx::lexer::parse_numeric_literal(token &tok) const if (exponent & 1) e *= *d; - if (tok.id == tokenid::float_literal) - tok.literal_as_float = exponent_negative ? fraction / static_cast(e) : fraction * static_cast(e); - else - tok.literal_as_double = exponent_negative ? fraction / e : fraction * e; - } - else - { - // Limit the maximum value to what fits into our token structure - tok.literal_as_uint = static_cast(fraction & 0xFFFFFFFF); + tok.literal_as_float = exponent_negative ? mantissa / static_cast(e) : mantissa * static_cast(e); +#else + std::from_chars(begin, end, tok.literal_as_float); +#endif } tok.length = end - begin; diff --git a/source/effect_parser_exp.cpp b/source/effect_parser_exp.cpp index f8ff56ffa8..333c5891f7 100644 --- a/source/effect_parser_exp.cpp +++ b/source/effect_parser_exp.cpp @@ -852,13 +852,6 @@ bool reshadefx::parser::parse_expression_unary(expression &exp) { exp.reset_to_rvalue_constant(location, _token.literal_as_float); } - else if (accept(tokenid::double_literal)) - { - // Convert double literal to float literal for now - warning(location, 5000, "double literal truncated to float literal"); - - exp.reset_to_rvalue_constant(location, static_cast(_token.literal_as_double)); - } else if (accept(tokenid::string_literal)) { std::string value = std::move(_token.literal_as_string); diff --git a/source/effect_token.hpp b/source/effect_token.hpp index e46f82cf98..2cc3cf646b 100644 --- a/source/effect_token.hpp +++ b/source/effect_token.hpp @@ -97,7 +97,6 @@ namespace reshadefx int_literal, uint_literal, float_literal, - double_literal, string_literal, // keywords @@ -270,7 +269,6 @@ namespace reshadefx int literal_as_int; unsigned int literal_as_uint; float literal_as_float; - double literal_as_double; }; std::string literal_as_string; diff --git a/source/imgui_code_editor.cpp b/source/imgui_code_editor.cpp index 879fd9fa55..51d404c1f5 100644 --- a/source/imgui_code_editor.cpp +++ b/source/imgui_code_editor.cpp @@ -1989,7 +1989,6 @@ void reshade::imgui::code_editor::colorize() case reshadefx::tokenid::int_literal: case reshadefx::tokenid::uint_literal: case reshadefx::tokenid::float_literal: - case reshadefx::tokenid::double_literal: col = color_number_literal; break; case reshadefx::tokenid::string_literal: diff --git a/source/input.cpp b/source/input.cpp index be6c957a38..6600e4c24e 100644 --- a/source/input.cpp +++ b/source/input.cpp @@ -121,7 +121,7 @@ std::string reshade::input::key_name(unsigned int keycode) if (keycode == key_home && is_keyboard_layout_german()) return "Pos1"; - static const char *keyboard_keys[256] = { + static const char *const keyboard_keys[256] = { "", "Left Mouse", "Right Mouse", "Cancel", "Middle Mouse", "X1 Mouse", "X2 Mouse", "", "Backspace", "Tab", "", "", "Clear", "Enter", "", "", "Shift", "Control", "Alt", "Pause", "Caps Lock", "", "", "", "", "", "", "Escape", "", "", "", "", "Space", "Page Up", "Page Down", "End", "Home", "Left Arrow", "Up Arrow", "Right Arrow", "Down Arrow", "Select", "", "", "Print Screen", "Insert", "Delete", "Help", diff --git a/source/input_windows.cpp b/source/input_windows.cpp index 03e973d763..d022aeb44a 100644 --- a/source/input_windows.cpp +++ b/source/input_windows.cpp @@ -656,7 +656,7 @@ extern "C" BOOL WINAPI HookGetCursorPosition(LPPOINT lpPoint) { assert(lpPoint != nullptr); - // Update position in case it is not overriden via 'SetCursorPos' + // Update position in case it is not overridden via 'SetCursorPos' s_last_cursor_position = *lpPoint; } diff --git a/source/opengl/opengl.cpp b/source/opengl/opengl.cpp index 32686357cc..21b779fd4f 100644 --- a/source/opengl/opengl.cpp +++ b/source/opengl/opengl.cpp @@ -841,7 +841,7 @@ extern "C" void APIENTRY glEnable(GLenum cap) reshade::has_addon_event()) { uint32_t value = GL_TRUE; - reshade::api::dynamic_state state = { reshade::api::dynamic_state::unknown }; + reshade::api::dynamic_state state = reshade::api::dynamic_state::unknown; switch (cap) { case GL_ALPHA_TEST: diff --git a/source/opengl/opengl_impl_command_list.cpp b/source/opengl/opengl_impl_command_list.cpp index d7e3ebb88d..35fb18e965 100644 --- a/source/opengl/opengl_impl_command_list.cpp +++ b/source/opengl/opengl_impl_command_list.cpp @@ -1200,7 +1200,7 @@ void reshade::opengl::device_context_impl::push_descriptors(api::shader_stage, a break; } } -void reshade::opengl::device_context_impl::bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) +void reshade::opengl::device_context_impl::bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t, const uint32_t *) { for (uint32_t i = 0; i < count; ++i) { diff --git a/source/opengl/opengl_impl_device_context.hpp b/source/opengl/opengl_impl_device_context.hpp index 3e01d33c95..b146d58ca3 100644 --- a/source/opengl/opengl_impl_device_context.hpp +++ b/source/opengl/opengl_impl_device_context.hpp @@ -48,7 +48,7 @@ namespace reshade::opengl void push_constants(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values) final; void push_descriptors(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update) final; - void bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) final; + void bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) final; void bind_index_buffer(api::resource buffer, uint64_t offset, uint32_t index_size) final; void bind_vertex_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides) final; diff --git a/source/opengl/opengl_impl_type_convert.cpp b/source/opengl/opengl_impl_type_convert.cpp index 9152c4d635..57d283cfd9 100644 --- a/source/opengl/opengl_impl_type_convert.cpp +++ b/source/opengl/opengl_impl_type_convert.cpp @@ -726,6 +726,8 @@ auto reshade::opengl::convert_pixel_format(const PIXELFORMATDESCRIPTOR &pfd) -> return api::format::b5g6r5_unorm; case 24: case 32: + if (pfd.cRedBits == 10 && pfd.cGreenBits == 10 && pfd.cBlueBits == 10) + return api::format::r10g10b10a2_unorm; if (pfd.cRedBits == 11 && pfd.cGreenBits == 11 && pfd.cBlueBits == 10) return api::format::r11g11b10_float; if (pfd.cAlphaBits != 0) diff --git a/source/runtime.cpp b/source/runtime.cpp index 7819bf2d79..7a3402d405 100644 --- a/source/runtime.cpp +++ b/source/runtime.cpp @@ -2826,8 +2826,7 @@ bool reshade::runtime::create_effect(size_t effect_index, size_t permutation_ind return true; exit_failure: - _device->free_descriptor_tables(static_cast(shader_resource_view_tables.size()), shader_resource_view_tables.data()); - _device->free_descriptor_tables(static_cast(unordered_access_view_tables.size()), unordered_access_view_tables.data()); + destroy_effect(effect_index, false); return false; } diff --git a/source/runtime_gui.cpp b/source/runtime_gui.cpp index 0643a811e4..0795a370c0 100644 --- a/source/runtime_gui.cpp +++ b/source/runtime_gui.cpp @@ -3427,7 +3427,7 @@ void reshade::runtime::draw_variable_editor() ImGui::SetWindowPos(popup_pos); bool global_modified = false, preset_modified = false; - float popup_height = (std::max(_global_preprocessor_definitions.size(), _preset_preprocessor_definitions[{}].size()) + 2) * ImGui::GetFrameHeightWithSpacing(); + float popup_height = (std::max(_global_preprocessor_definitions.size(), _preset_preprocessor_definitions[{}].size()) + 3) * ImGui::GetFrameHeightWithSpacing(); popup_height = std::min(popup_height, ImGui::GetWindowViewport()->Size.y - popup_pos.y - 20.0f); popup_height = std::max(popup_height, 42.0f); // Ensure window always has a minimum height const float button_size = ImGui::GetFrameHeight(); @@ -3453,6 +3453,12 @@ void reshade::runtime::draw_variable_editor() { if (ImGui::BeginTabItem(type.name.c_str())) { + ImGui::Dummy(ImVec2()); + ImGui::SameLine(0, button_spacing); + ImGui::TextUnformatted(_("Name")); + ImGui::SameLine(content_region_width * 0.66666666f, button_spacing); + ImGui::TextUnformatted(_("Value")); + if (&type.modified == &preset_modified) ImGui::BeginDisabled(!_auto_save_preset); @@ -4682,7 +4688,7 @@ void reshade::runtime::draw_code_editor(editor_instance &instance) bool reshade::runtime::init_imgui_resources() { // Adjust default font size based on the vertical resolution - if (_font_size == 13.0f) + if (_font_size == 13.0f && _imgui_context->Style.FontScaleMain == 1.0f) _imgui_context->Style.FontScaleMain = _height >= 2160 ? 2.0f : _height >= 1440 ? 1.5f : 1.0f; const bool has_combined_sampler_and_view = _device->check_capability(api::device_caps::sampler_with_resource_view); diff --git a/source/vulkan/vulkan_hooks.hpp b/source/vulkan/vulkan_hooks.hpp index ae5f42ef54..6e42fdb7e8 100644 --- a/source/vulkan/vulkan_hooks.hpp +++ b/source/vulkan/vulkan_hooks.hpp @@ -21,13 +21,11 @@ inline T *find_layer_info(const void *structure_chain, VkStructureType type, VkL next = reinterpret_cast(const_cast(next->pNext)); return next; } -template -inline const T *find_in_structure_chain(const void *structure_chain, VkStructureType type) + +inline void append_to_structure_chain(void *structure_chain, void *new_structure) { - const T *next = reinterpret_cast(structure_chain); - while (next != nullptr && next->sType != type) - next = reinterpret_cast(next->pNext); - return next; + static_cast(new_structure)->pNext = static_cast(structure_chain)->pNext; + static_cast(structure_chain)->pNext = static_cast(new_structure); } inline void *const dispatch_key_from_handle(const void *dispatch_handle) diff --git a/source/vulkan/vulkan_hooks_command_list.cpp b/source/vulkan/vulkan_hooks_command_list.cpp index 1f883942f8..2f7c1748aa 100644 --- a/source/vulkan/vulkan_hooks_command_list.cpp +++ b/source/vulkan/vulkan_hooks_command_list.cpp @@ -79,7 +79,8 @@ static bool invoke_begin_render_pass_event(const reshade::vulkan::device_impl *d std::copy_n(begin_info->pClearValues[a].color.float32, 4, rt.clear_color); } - if (desc.initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && desc.initialLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + if (desc.initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && + desc.initialLayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { VkImageMemoryBarrier &transition = transitions[num_transitions++]; transition = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; @@ -124,7 +125,10 @@ static bool invoke_begin_render_pass_event(const reshade::vulkan::device_impl *d ds.clear_stencil = static_cast(begin_info->pClearValues[a].depthStencil.stencil); } - if (desc.initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && desc.initialLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + if (desc.initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && + desc.initialLayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL && + desc.initialLayout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL && + desc.initialLayout != VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL) { VkImageMemoryBarrier &transition = transitions[num_transitions++]; transition = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; @@ -458,7 +462,8 @@ void VKAPI_CALL vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelin reshade::vulkan::convert_shader_stages(pipelineBindPoint), reshade::api::pipeline_layout { (uint64_t)layout }, firstSet, descriptorSetCount, - reinterpret_cast(pDescriptorSets)); + reinterpret_cast(pDescriptorSets), + dynamicOffsetCount, pDynamicOffsets); #endif } @@ -1197,7 +1202,7 @@ void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContent if (cmd_impl->_is_in_render_pass & 0x80) { - // Render pass was overriden by an add-on, so there are no subpasses + // Render pass was overridden by an add-on, so there are no subpasses return; } @@ -1240,7 +1245,7 @@ void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer) } if (cmd_impl->_is_in_render_pass & 0x80) { - // Render pass was overriden by an add-on, so need to end it the same way + // Render pass was overridden by an add-on, so need to end it the same way cmd_impl->end_render_pass(); return; } @@ -1338,7 +1343,7 @@ void VKAPI_CALL vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpass if (cmd_impl->_is_in_render_pass & 0x80) { - // Render pass was overriden by an add-on, so there are no subpasses + // Render pass was overridden by an add-on, so there are no subpasses return; } @@ -1382,7 +1387,7 @@ void VKAPI_CALL vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpa } if (cmd_impl->_is_in_render_pass & 0x80) { - // Render pass was overriden by an add-on, so need to end it the same way + // Render pass was overridden by an add-on, so need to end it the same way cmd_impl->end_render_pass(); return; } @@ -1798,7 +1803,7 @@ void VKAPI_CALL vkCmdEndRendering(VkCommandBuffer commandBuffer) } if (cmd_impl->_is_in_render_pass & 0x80) { - // Render pass was overriden by an add-on, so need to end it the same way + // Render pass was overridden by an add-on, so need to end it the same way cmd_impl->end_render_pass(); return; } diff --git a/source/vulkan/vulkan_hooks_device.cpp b/source/vulkan/vulkan_hooks_device.cpp index cf04d5f191..7aef85f4d6 100644 --- a/source/vulkan/vulkan_hooks_device.cpp +++ b/source/vulkan/vulkan_hooks_device.cpp @@ -17,7 +17,7 @@ #include // std::strcmp, std::strncmp #include // std::find_if, std::min -// Set during Vulkan device creation and presentation, to avoid hooking internal D3D devices created e.g. by NVIDIA Ansel, Optimus or layered DXGI swapchain +// Set during Vulkan device creation and presentation, to avoid hooking internal D3D devices created e.g. by NVIDIA Ansel, Optimus or layered DXGI swap chain extern thread_local bool g_in_dxgi_runtime; extern lockfree_linear_map g_vulkan_instances; @@ -62,6 +62,22 @@ void destroy_default_view(reshade::vulkan::device_impl *device_impl, VkImage ima } #endif +struct VkLayerDeviceLink +{ + VkLayerDeviceLink *pNext; + PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; + PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr; +}; +struct VkLayerDeviceCreateInfo +{ + VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO + const void *pNext; + VkLayerFunction function; + union { + VkLayerDeviceLink *pLayerInfo; + } u; +}; + VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) { reshade::log::message(reshade::log::level::info, "Redirecting vkCreateDevice(physicalDevice = %p, pCreateInfo = %p, pAllocator = %p, pDevice = %p) ...", physicalDevice, pCreateInfo, pAllocator, pDevice); @@ -69,22 +85,6 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi assert(pCreateInfo != nullptr && pDevice != nullptr); // Look for layer link info if installed as a layer (provided by the Vulkan loader) - struct VkLayerDeviceLink - { - VkLayerDeviceLink *pNext; - PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; - PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr; - }; - struct VkLayerDeviceCreateInfo - { - VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - const void *pNext; - VkLayerFunction function; - union { - VkLayerDeviceLink *pLayerInfo; - } u; - }; - const auto link_info = find_layer_info(pCreateInfo->pNext, VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO, VK_LAYER_LINK_INFO); const vulkan_instance &instance = g_vulkan_instances.at(dispatch_key_from_handle(physicalDevice)); @@ -130,28 +130,6 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi if (enum_queue_families == nullptr || enum_device_extensions == nullptr) return VK_ERROR_INITIALIZATION_FAILED; - uint32_t num_queue_families = 0; - enum_queue_families(physicalDevice, &num_queue_families, nullptr); - std::vector queue_families(num_queue_families); - enum_queue_families(physicalDevice, &num_queue_families, queue_families.data()); - - uint32_t graphics_queue_family_index = std::numeric_limits::max(); - for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) - { - const uint32_t queue_family_index = pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex; - assert(queue_family_index < num_queue_families); - - // Find the first queue family which supports graphics and has at least one queue - if (pCreateInfo->pQueueCreateInfos[i].queueCount > 0 && (queue_families[queue_family_index].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) - { - if (pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[0] < 1.0f) - reshade::log::message(reshade::log::level::warning, "Vulkan queue used for rendering has a low priority (%f).", pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[0]); - - graphics_queue_family_index = queue_family_index; - break; - } - } - VkPhysicalDeviceFeatures enabled_features = {}; const VkPhysicalDeviceFeatures2 *const features2 = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2); @@ -165,23 +143,59 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; ++i) enabled_extensions.push_back(pCreateInfo->ppEnabledExtensionNames[i]); - bool buffer_device_address_ext = false; - bool timeline_semaphore_ext = false; - bool host_query_reset_ext = false; - bool dynamic_rendering_ext = false; - bool extended_dynamic_state_ext = false; - bool push_descriptor_ext = false; - bool host_image_copy_ext = false; - bool custom_border_color_ext = false; - bool conservative_rasterization_ext = false; - bool ray_tracing_ext = false; - bool descriptor_indexing_ext = false; + struct + { + uint32_t host_query_reset : 1; + uint32_t timeline_semaphore : 1; + uint32_t buffer_device_address : 1; + uint32_t dynamic_rendering : 1; + uint32_t extended_dynamic_state : 1; + uint32_t push_descriptor : 1; + uint32_t host_image_copy : 1; + uint32_t custom_border_color : 1; + uint32_t conservative_rasterization : 1; + uint32_t ray_tracing : 1; + uint32_t descriptor_indexing : 1; + + VkPhysicalDeviceHostQueryResetFeatures host_query_reset_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES }; + VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES }; + VkPhysicalDeviceBufferDeviceAddressFeatures buffer_device_address_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES }; + VkPhysicalDevicePrivateDataFeatures private_data_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES }; + VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES }; + VkPhysicalDeviceMaintenance5Features maintenance5_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES }; + VkPhysicalDeviceHostImageCopyFeatures host_image_copy_features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES }; + } ext = {}; + std::vector queue_families; + uint32_t graphics_queue_family_index = std::numeric_limits::max(); + + { + uint32_t num_queue_families = 0; + enum_queue_families(physicalDevice, &num_queue_families, nullptr); + queue_families.resize(num_queue_families); + enum_queue_families(physicalDevice, &num_queue_families, queue_families.data()); + + for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; ++i) + { + const uint32_t queue_family_index = pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex; + assert(queue_family_index < num_queue_families); + + // Find the first queue family which supports graphics and has at least one queue + if (pCreateInfo->pQueueCreateInfos[i].queueCount > 0 && (queue_families[queue_family_index].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) + { + if (pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[0] < 1.0f) + reshade::log::message(reshade::log::level::warning, "Vulkan queue used for rendering has a low priority (%f).", pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[0]); + + graphics_queue_family_index = queue_family_index; + break; + } + } + } { - uint32_t num_extensions = 0; - enum_device_extensions(physicalDevice, nullptr, &num_extensions, nullptr); - std::vector extensions(num_extensions); - enum_device_extensions(physicalDevice, nullptr, &num_extensions, extensions.data()); + uint32_t num_device_extensions = 0; + enum_device_extensions(physicalDevice, nullptr, &num_device_extensions, nullptr); + std::vector extensions(num_device_extensions); + enum_device_extensions(physicalDevice, nullptr, &num_device_extensions, extensions.data()); // Make sure the driver actually supports the requested extensions const auto add_extension = [&extensions, &enabled_extensions, &graphics_queue_family_index](const char *name, bool required) { @@ -208,7 +222,6 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi return false; }; - #pragma region Enable features and extensions // Enable features that ReShade requires enabled_features.samplerAnisotropy = VK_TRUE; enabled_features.shaderImageGatherExtended = VK_TRUE; @@ -219,17 +232,25 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi if (instance.api_version < VK_API_VERSION_1_2) { #if VK_KHR_timeline_semaphore - timeline_semaphore_ext = add_extension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, false); + ext.timeline_semaphore = + add_extension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, true); #endif + #if VK_EXT_host_query_reset - host_query_reset_ext = add_extension(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, false); + ext.host_query_reset = + add_extension(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, false); #endif } if (instance.api_version < VK_API_VERSION_1_3) { +#if VK_EXT_private_data + if (!add_extension(VK_EXT_PRIVATE_DATA_EXTENSION_NAME, true)) +#endif + return VK_ERROR_EXTENSION_NOT_PRESENT; + #if VK_KHR_dynamic_rendering - dynamic_rendering_ext = + ext.dynamic_rendering = add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, false) && // Add extensions that are required by VK_KHR_dynamic_rendering when not using the core variant add_extension(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, false) && @@ -237,22 +258,17 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi #endif #if VK_EXT_extended_dynamic_state - extended_dynamic_state_ext = add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); -#endif - -#if VK_EXT_private_data - if (!add_extension(VK_EXT_PRIVATE_DATA_EXTENSION_NAME, true)) + ext.extended_dynamic_state = + add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); #endif - return VK_ERROR_EXTENSION_NOT_PRESENT; } if (instance.api_version < VK_API_VERSION_1_4) { -#if VK_KHR_push_descriptor - push_descriptor_ext = add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, false); -#endif + add_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME, true); + #if VK_EXT_host_image_copy - host_image_copy_ext = + ext.host_image_copy = add_extension(VK_EXT_HOST_IMAGE_COPY_EXTENSION_NAME, false) && // Add extensions that are required by VK_EXT_host_image_copy when not using the core variant add_extension(VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME, false) && @@ -260,28 +276,14 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi #endif } +#if VK_KHR_push_descriptor + ext.push_descriptor = + add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, false); +#endif + #if VK_KHR_external_memory_win32 add_extension(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, false); #endif -#if VK_EXT_custom_border_color - custom_border_color_ext = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); -#endif -#if VK_EXT_conservative_rasterization - conservative_rasterization_ext = add_extension(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME, false); -#endif - -#if 0 - ray_tracing_ext = - add_extension(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, false) && - add_extension(VK_KHR_SPIRV_1_4_EXTENSION_NAME, false) && - add_extension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false) && - add_extension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, false) && - add_extension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, false) && - add_extension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false) && - add_extension(VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME, false); - buffer_device_address_ext = ray_tracing_ext && add_extension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, false); -#endif - #pragma endregion // Check if the device is used for presenting if (std::find_if(enabled_extensions.cbegin(), enabled_extensions.cend(), @@ -313,162 +315,137 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi create_info.enabledExtensionCount = static_cast(enabled_extensions.size()); create_info.ppEnabledExtensionNames = enabled_extensions.data(); + VkDevicePrivateDataCreateInfo private_data_info { VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO }; + private_data_info.privateDataSlotRequestCount = 1; + append_to_structure_chain(&create_info, &private_data_info); + #pragma region Patch the enabled features // Patch the enabled features if (features2 != nullptr) - // This is evil, because overwriting application memory, but whatever (RenderDoc does this too) const_cast(features2)->features = enabled_features; else create_info.pEnabledFeatures = &enabled_features; - VkPhysicalDeviceHostQueryResetFeatures host_query_reset_features; - VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore_features; - VkPhysicalDeviceBufferDeviceAddressFeatures buffer_device_address_features; if (const auto existing_vulkan_12_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES)) { assert(instance.api_version >= VK_API_VERSION_1_2); - buffer_device_address_ext = existing_vulkan_12_features->bufferDeviceAddress; - + ext.host_query_reset = existing_vulkan_12_features->hostQueryReset; // Force enable timeline semaphore support (used for effect runtime present/graphics queue synchronization in case of present from compute, e.g. in Indiana Jones and the Great Circle and DOOM Eternal) - timeline_semaphore_ext = true; - const_cast(existing_vulkan_12_features)->timelineSemaphore = VK_TRUE; - - host_query_reset_ext = existing_vulkan_12_features->hostQueryReset; - descriptor_indexing_ext = existing_vulkan_12_features->descriptorIndexing; + ext.timeline_semaphore = const_cast(existing_vulkan_12_features)->timelineSemaphore = VK_TRUE; + ext.descriptor_indexing = existing_vulkan_12_features->descriptorIndexing; + ext.buffer_device_address = existing_vulkan_12_features->bufferDeviceAddress; } else { -#if VK_EXT_descriptor_indexing - if (const auto existing_descriptor_indexing_features = find_in_structure_chain( - pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES)) - { - descriptor_indexing_ext = existing_descriptor_indexing_features->descriptorBindingPartiallyBound || - existing_descriptor_indexing_features->descriptorBindingUniformBufferUpdateAfterBind || - existing_descriptor_indexing_features->descriptorBindingSampledImageUpdateAfterBind || - existing_descriptor_indexing_features->descriptorBindingStorageImageUpdateAfterBind || - existing_descriptor_indexing_features->descriptorBindingStorageBufferUpdateAfterBind || - existing_descriptor_indexing_features->descriptorBindingUniformTexelBufferUpdateAfterBind || - existing_descriptor_indexing_features->descriptorBindingStorageTexelBufferUpdateAfterBind || - existing_descriptor_indexing_features->descriptorBindingUpdateUnusedWhilePending || - existing_descriptor_indexing_features->descriptorBindingVariableDescriptorCount || - existing_descriptor_indexing_features->runtimeDescriptorArray; - } -#endif - - if (const auto existing_buffer_device_address_features = find_in_structure_chain( - pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES)) + if (const auto existing_host_query_reset_features = find_in_structure_chain( + pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES)) { - buffer_device_address_ext = existing_buffer_device_address_features->bufferDeviceAddress; + ext.host_query_reset = existing_host_query_reset_features->hostQueryReset; } - else if (buffer_device_address_ext) + else if (ext.host_query_reset) { - buffer_device_address_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, const_cast(create_info.pNext) }; - buffer_device_address_features.bufferDeviceAddress = VK_TRUE; - - create_info.pNext = &buffer_device_address_features; + append_to_structure_chain(&create_info, &ext.host_query_reset_features); + ext.host_query_reset_features.hostQueryReset = VK_TRUE; } if (const auto existing_timeline_semaphore_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES)) { - timeline_semaphore_ext = true; - const_cast(existing_timeline_semaphore_features)->timelineSemaphore = VK_TRUE; + ext.timeline_semaphore = const_cast(existing_timeline_semaphore_features)->timelineSemaphore = VK_TRUE; } - else if (timeline_semaphore_ext) + else if (ext.timeline_semaphore) { - timeline_semaphore_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, const_cast(create_info.pNext) }; - timeline_semaphore_features.timelineSemaphore = VK_TRUE; - - create_info.pNext = &timeline_semaphore_features; + append_to_structure_chain(&create_info, &ext.timeline_semaphore_features); + ext.timeline_semaphore_features.timelineSemaphore = VK_TRUE; } - if (const auto existing_host_query_reset_features = find_in_structure_chain( - pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES)) + if (const auto existing_buffer_device_address_features = find_in_structure_chain( + pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES)) { - host_query_reset_ext = existing_host_query_reset_features->hostQueryReset; + ext.buffer_device_address = existing_buffer_device_address_features->bufferDeviceAddress; } - else if (host_query_reset_ext) + else if (ext.buffer_device_address) { - host_query_reset_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, const_cast(create_info.pNext) }; - host_query_reset_features.hostQueryReset = VK_TRUE; + append_to_structure_chain(&create_info, &ext.buffer_device_address_features); + ext.buffer_device_address_features.bufferDeviceAddress = VK_TRUE; + } - create_info.pNext = &host_query_reset_features; + if (const auto existing_descriptor_indexing_features = find_in_structure_chain( + pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES)) + { + ext.descriptor_indexing = existing_descriptor_indexing_features->descriptorBindingPartiallyBound || existing_descriptor_indexing_features->descriptorBindingUniformBufferUpdateAfterBind || existing_descriptor_indexing_features->descriptorBindingSampledImageUpdateAfterBind || existing_descriptor_indexing_features->descriptorBindingStorageImageUpdateAfterBind || existing_descriptor_indexing_features->descriptorBindingStorageBufferUpdateAfterBind || existing_descriptor_indexing_features->descriptorBindingUniformTexelBufferUpdateAfterBind || existing_descriptor_indexing_features->descriptorBindingStorageTexelBufferUpdateAfterBind || existing_descriptor_indexing_features->descriptorBindingUpdateUnusedWhilePending || existing_descriptor_indexing_features->descriptorBindingVariableDescriptorCount || existing_descriptor_indexing_features->runtimeDescriptorArray ? 1 : 0; } } - // Enable private data feature - VkDevicePrivateDataCreateInfo private_data_info { VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, create_info.pNext }; - private_data_info.privateDataSlotRequestCount = 1; - - VkPhysicalDevicePrivateDataFeatures private_data_features; - VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering_features; if (const auto existing_vulkan_13_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES)) { assert(instance.api_version >= VK_API_VERSION_1_3); - create_info.pNext = &private_data_info; - - dynamic_rendering_ext = existing_vulkan_13_features->dynamicRendering; - - // Forcefully enable private data in Vulkan 1.3, again, evil =) const_cast(existing_vulkan_13_features)->privateData = VK_TRUE; + + ext.dynamic_rendering = existing_vulkan_13_features->dynamicRendering; } else { if (const auto existing_private_data_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES)) { - create_info.pNext = &private_data_info; - const_cast(existing_private_data_features)->privateData = VK_TRUE; } else { - private_data_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, &private_data_info }; - private_data_features.privateData = VK_TRUE; - - create_info.pNext = &private_data_features; + append_to_structure_chain(&create_info, &ext.private_data_features); + ext.private_data_features.privateData = VK_TRUE; } if (const auto existing_dynamic_rendering_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES)) { - dynamic_rendering_ext = existing_dynamic_rendering_features->dynamicRendering; + ext.dynamic_rendering = existing_dynamic_rendering_features->dynamicRendering; } - else if (dynamic_rendering_ext) + else if (ext.dynamic_rendering) { - dynamic_rendering_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, const_cast(create_info.pNext) }; - dynamic_rendering_features.dynamicRendering = VK_TRUE; - - create_info.pNext = &dynamic_rendering_features; + append_to_structure_chain(&create_info, &ext.dynamic_rendering_features); + ext.dynamic_rendering_features.dynamicRendering = VK_TRUE; } } - VkPhysicalDeviceHostImageCopyFeatures host_image_copy_features; if (const auto existing_vulkan_14_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES)) { assert(instance.api_version >= VK_API_VERSION_1_4); - push_descriptor_ext = existing_vulkan_14_features->pushDescriptor; - host_image_copy_ext = existing_vulkan_14_features->hostImageCopy; + const_cast(existing_vulkan_14_features)->maintenance5 = VK_TRUE; + if (ext.push_descriptor) + const_cast(existing_vulkan_14_features)->pushDescriptor = VK_TRUE; + + ext.host_image_copy = existing_vulkan_14_features->hostImageCopy; } else { + if (const auto existing_maintenance5_features = find_in_structure_chain( + pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES)) + { + const_cast(existing_maintenance5_features)->maintenance5 = VK_TRUE; + } + else + { + append_to_structure_chain(&create_info, &ext.maintenance5_features); + ext.maintenance5_features.maintenance5 = VK_TRUE; + } + if (const auto existing_host_image_copy_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES)) { - host_image_copy_ext = existing_host_image_copy_features->hostImageCopy; + ext.host_image_copy = existing_host_image_copy_features->hostImageCopy; } - else if (host_image_copy_ext) + else if (ext.host_image_copy) { - host_image_copy_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES, const_cast(create_info.pNext) }; - host_image_copy_features.hostImageCopy = VK_TRUE; - - create_info.pNext = &host_image_copy_features; + append_to_structure_chain(&create_info, &ext.host_image_copy_features); + ext.host_image_copy_features.hostImageCopy = VK_TRUE; } } @@ -481,60 +458,26 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi } #if VK_EXT_custom_border_color - // Optionally enable custom border color feature - VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border_features; if (const auto existing_custom_border_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT)) { - custom_border_color_ext = existing_custom_border_features->customBorderColors; - } - else if (custom_border_color_ext) - { - custom_border_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, const_cast(create_info.pNext) }; - custom_border_features.customBorderColors = VK_TRUE; - custom_border_features.customBorderColorWithoutFormat = VK_TRUE; - - create_info.pNext = &custom_border_features; + ext.custom_border_color = existing_custom_border_features->customBorderColors; } #endif #if VK_EXT_extended_dynamic_state - // Optionally enable extended dynamic state feature - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extended_dynamic_state_features; if (const auto existing_extended_dynamic_state_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT)) { - extended_dynamic_state_ext = existing_extended_dynamic_state_features->extendedDynamicState; - } - else if (extended_dynamic_state_ext) - { - extended_dynamic_state_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, const_cast(create_info.pNext) }; - extended_dynamic_state_features.extendedDynamicState = VK_TRUE; - - create_info.pNext = &extended_dynamic_state_features; + ext.extended_dynamic_state = existing_extended_dynamic_state_features->extendedDynamicState; } #endif #if VK_KHR_acceleration_structure && VK_KHR_ray_tracing_pipeline - // Optionally enable ray tracing feature - VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray_tracing_features; - VkPhysicalDeviceAccelerationStructureFeaturesKHR acceleration_structure_features; if (const auto existing_ray_tracing_features = find_in_structure_chain( pCreateInfo->pNext, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR)) { - ray_tracing_ext = existing_ray_tracing_features->rayTracingPipeline; - } - else if (ray_tracing_ext) - { - ray_tracing_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR, const_cast(create_info.pNext) }; - ray_tracing_features.rayTracingPipeline = VK_TRUE; - - create_info.pNext = &ray_tracing_features; - - acceleration_structure_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR, const_cast(create_info.pNext) }; - acceleration_structure_features.accelerationStructure = VK_TRUE; - - create_info.pNext = &acceleration_structure_features; + ext.ray_tracing = existing_ray_tracing_features->rayTracingPipeline; } #endif #pragma endregion @@ -600,40 +543,40 @@ VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDevi #pragma region Initialize features and extensions #if VK_KHR_buffer_device_address - device.dispatch_table.KHR_buffer_device_address &= buffer_device_address_ext ? 1 : 0; + device.dispatch_table.KHR_buffer_device_address &= ext.buffer_device_address; #endif #if VK_KHR_timeline_semaphore - device.dispatch_table.KHR_timeline_semaphore &= timeline_semaphore_ext ? 1 : 0; + device.dispatch_table.KHR_timeline_semaphore &= ext.timeline_semaphore; #endif #if VK_KHR_dynamic_rendering - device.dispatch_table.KHR_dynamic_rendering &= dynamic_rendering_ext ? 1 : 0; + device.dispatch_table.KHR_dynamic_rendering &= ext.dynamic_rendering; #endif #if VK_KHR_push_descriptor - device.dispatch_table.KHR_push_descriptor &= push_descriptor_ext ? 1 : 0; + device.dispatch_table.KHR_push_descriptor &= ext.push_descriptor; #endif #if VK_KHR_ray_tracing_pipeline - device.dispatch_table.KHR_ray_tracing_pipeline &= ray_tracing_ext ? 1 : 0; + device.dispatch_table.KHR_ray_tracing_pipeline &= ext.ray_tracing; #endif #if VK_KHR_acceleration_structure - device.dispatch_table.KHR_acceleration_structure &= ray_tracing_ext ? 1 : 0; + device.dispatch_table.KHR_acceleration_structure &= ext.ray_tracing; #endif #if VK_EXT_host_query_reset - device.dispatch_table.EXT_host_query_reset &= host_query_reset_ext ? 1 : 0; + device.dispatch_table.EXT_host_query_reset &= ext.host_query_reset; #endif #if VK_EXT_extended_dynamic_state - device.dispatch_table.EXT_extended_dynamic_state &= extended_dynamic_state_ext ? 1 : 0; + device.dispatch_table.EXT_extended_dynamic_state &= ext.extended_dynamic_state; #endif #if VK_EXT_host_image_copy - device.dispatch_table.EXT_host_image_copy &= host_image_copy_ext ? 1 : 0; + device.dispatch_table.EXT_host_image_copy &= ext.host_image_copy; #endif #if VK_EXT_custom_border_color - device.dispatch_table.EXT_custom_border_color &= custom_border_color_ext ? 1 : 0; + device.dispatch_table.EXT_custom_border_color &= ext.custom_border_color; #endif #if VK_EXT_conservative_rasterization - device.dispatch_table.EXT_conservative_rasterization &= conservative_rasterization_ext ? 1 : 0; + device.dispatch_table.EXT_conservative_rasterization &= ext.conservative_rasterization; #endif #if VK_EXT_descriptor_indexing - device.dispatch_table.EXT_descriptor_indexing &= descriptor_indexing_ext ? 1 : 0; + device.dispatch_table.EXT_descriptor_indexing &= ext.descriptor_indexing; #endif if (instance.api_version < VK_API_VERSION_1_2) @@ -1225,13 +1168,15 @@ VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo *pCre reshade::vulkan::convert_resource_desc(desc, create_info); pCreateInfo = &create_info; - // Remove format list info if format was overriden + // Remove format list info if format was overridden if (const auto existing_format_list_info = find_in_structure_chain( create_info.pNext, VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO)) { - if (std::find(existing_format_list_info->pViewFormats, existing_format_list_info->pViewFormats + existing_format_list_info->viewFormatCount, create_info.format) == (existing_format_list_info->pViewFormats + existing_format_list_info->viewFormatCount)) - // This is evil, because writing into application memory, but it is what it is + if (const VkFormat *const formats_begin = existing_format_list_info->pViewFormats, *const formats_end = existing_format_list_info->pViewFormats + existing_format_list_info->viewFormatCount; + std::find(formats_begin, formats_end, create_info.format) == formats_end) + { const_cast(existing_format_list_info)->viewFormatCount = 0; + } } } #endif @@ -1379,6 +1324,10 @@ VkResult VKAPI_CALL vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache p RESHADE_VULKAN_GET_DEVICE_DISPATCH_PTR(CreateGraphicsPipelines, device_impl); #if RESHADE_ADDON >= 2 + // Disable custom allocator when pipeline may be overridden, so corresponding 'vkDestroyPipeline' is not called with mismatching callbacks + if (reshade::has_addon_event()) + pAllocator = nullptr; + VkResult result = VK_SUCCESS; for (uint32_t i = 0; i < createInfoCount; ++i) { @@ -1602,15 +1551,12 @@ VkResult VKAPI_CALL vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache p subobjects.push_back({ reshade::api::pipeline_subobject_type::sample_count, 1, &sample_count }); } - if (pAllocator == nullptr && // Cannot replace pipeline if custom allocator is used, since corresponding 'vkDestroyPipeline' would be called with mismatching allocator callbacks - reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data())) + if (reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data())) { static_assert(sizeof(*pPipelines) == sizeof(reshade::api::pipeline)); - assert(create_info.pNext == nullptr); // 'device_impl::create_pipeline' does not support extension structures apart from dynamic rendering - result = device_impl->create_pipeline( - reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data(), reinterpret_cast(&pPipelines[i])) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data(), reinterpret_cast(&pPipelines[i]), &create_info) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; } else { @@ -1647,6 +1593,10 @@ VkResult VKAPI_CALL vkCreateComputePipelines(VkDevice device, VkPipelineCache pi RESHADE_VULKAN_GET_DEVICE_DISPATCH_PTR(CreateComputePipelines, device_impl); #if RESHADE_ADDON >= 2 + // Disable custom allocator when pipeline may be overridden, so corresponding 'vkDestroyPipeline' is not called with mismatching callbacks + if (reshade::has_addon_event()) + pAllocator = nullptr; + VkResult result = VK_SUCCESS; for (uint32_t i = 0; i < createInfoCount; ++i) { @@ -1687,11 +1637,10 @@ VkResult VKAPI_CALL vkCreateComputePipelines(VkDevice device, VkPipelineCache pi { reshade::api::pipeline_subobject_type::flags, 1, &flags } }; - if (pAllocator == nullptr && // Cannot replace pipeline if custom allocator is used, since corresponding 'vkDestroyPipeline' would be called with mismatching allocator callbacks - reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(std::size(subobjects)), subobjects)) + if (reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(std::size(subobjects)), subobjects)) { result = device_impl->create_pipeline( - reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(std::size(subobjects)), subobjects, reinterpret_cast(&pPipelines[i])) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(std::size(subobjects)), subobjects, reinterpret_cast(&pPipelines[i]), &create_info) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; } else { @@ -1729,6 +1678,10 @@ VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOp RESHADE_VULKAN_GET_DEVICE_DISPATCH_PTR(CreateRayTracingPipelinesKHR, device_impl); #if RESHADE_ADDON >= 2 + // Disable custom allocator when pipeline may be overridden, so corresponding 'vkDestroyPipeline' is not called with mismatching callbacks + if (reshade::has_addon_event()) + pAllocator = nullptr; + VkResult result = VK_SUCCESS; for (uint32_t i = 0; i < createInfoCount; ++i) { @@ -1874,16 +1827,14 @@ VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOp subobjects.push_back({ reshade::api::pipeline_subobject_type::max_attribute_size, 1, const_cast(&create_info.pLibraryInterface->maxPipelineRayHitAttributeSize) }); } - if (pAllocator == nullptr && // Cannot replace pipeline if custom allocator is used, since corresponding 'vkDestroyPipeline' would be called with mismatching allocator callbacks - reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data())) + if (reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data())) { static_assert(sizeof(*pPipelines) == sizeof(reshade::api::pipeline)); assert(deferredOperation == VK_NULL_HANDLE); - assert(create_info.pNext == nullptr); // 'device_impl::create_pipeline' does not support extension structures result = device_impl->create_pipeline( - reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data(), reinterpret_cast(&pPipelines[i])) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + reshade::api::pipeline_layout { (uint64_t)create_info.layout }, static_cast(subobjects.size()), subobjects.data(), reinterpret_cast(&pPipelines[i]), &create_info) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; } else { @@ -1926,7 +1877,7 @@ void VKAPI_CALL vkDestroyPipeline(VkDevice device, VkPipeline pipeline, cons #if RESHADE_ADDON >= 2 reshade::invoke_addon_event(device_impl, reshade::api::pipeline { (uint64_t)pipeline }); - if (pAllocator == nullptr) + if (reshade::has_addon_event()) { device_impl->destroy_pipeline(reshade::api::pipeline { (uint64_t)pipeline }); return; @@ -1945,7 +1896,11 @@ VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayo VkResult result = VK_SUCCESS; #if RESHADE_ADDON >= 2 - bool created_via_addon_event = false; + // Disable custom allocator when pipeline layout may be overridden, so corresponding 'vkDestroyPipelineLayout' is not called with mismatching callbacks + if (reshade::has_addon_event()) + pAllocator = nullptr; + + bool owns_set_layouts = false; const uint32_t set_desc_count = pCreateInfo->setLayoutCount; uint32_t param_count = set_desc_count + pCreateInfo->pushConstantRangeCount; @@ -2007,15 +1962,12 @@ VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayo reshade::api::pipeline_layout_param *param_data = params.data(); - if (pAllocator == nullptr && // Cannot replace pipeline layout if custom allocator is used, since corresponding 'vkDestroyPipelineLayout' would be called with mismatching allocator callbacks - reshade::invoke_addon_event(device_impl, param_count, param_data)) + if (reshade::invoke_addon_event(device_impl, param_count, param_data)) { static_assert(sizeof(*pPipelineLayout) == sizeof(reshade::api::pipeline_layout)); - assert(pCreateInfo->pNext == nullptr); // 'device_impl::create_pipeline_layout' does not support extension structures - - result = device_impl->create_pipeline_layout(param_count, param_data, reinterpret_cast(pPipelineLayout)) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; - created_via_addon_event = result == VK_SUCCESS; + result = device_impl->create_pipeline_layout(param_count, param_data, reinterpret_cast(pPipelineLayout), pCreateInfo) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + owns_set_layouts = true; } else #endif @@ -2032,7 +1984,7 @@ VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayo } #if RESHADE_ADDON >= 2 - if (!created_via_addon_event) + if (!owns_set_layouts) { reshade::vulkan::object_data &data = *device_impl->register_object(*pPipelineLayout); data.set_layouts.assign(pCreateInfo->pSetLayouts, pCreateInfo->pSetLayouts + pCreateInfo->setLayoutCount); @@ -2055,13 +2007,15 @@ void VKAPI_CALL vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pi #if RESHADE_ADDON >= 2 reshade::invoke_addon_event(device_impl, reshade::api::pipeline_layout { (uint64_t)pipelineLayout }); - if (pAllocator == nullptr) + if (reshade::has_addon_event()) { // Clean up any samplers and descriptor set layouts that may have been created when an add-on modified the creation of the pipeline layout device_impl->destroy_pipeline_layout(reshade::api::pipeline_layout { (uint64_t)pipelineLayout }); return; } + assert(!device_impl->get_private_data_for_object(pipelineLayout)->owns_set_layouts); + device_impl->unregister_object(pipelineLayout); #endif diff --git a/source/vulkan/vulkan_hooks_instance.cpp b/source/vulkan/vulkan_hooks_instance.cpp index 5d939f89df..313ba93e69 100644 --- a/source/vulkan/vulkan_hooks_instance.cpp +++ b/source/vulkan/vulkan_hooks_instance.cpp @@ -16,6 +16,22 @@ lockfree_linear_map g_vulkan_surfaces; lockfree_linear_map g_vulkan_instances; +struct VkLayerInstanceLink +{ + VkLayerInstanceLink *pNext; + PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; + PFN_vkGetInstanceProcAddr pfnNextGetPhysicalDeviceProcAddr; +}; +struct VkLayerInstanceCreateInfo +{ + VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO + const void *pNext; + VkLayerFunction function; + union { + VkLayerInstanceLink *pLayerInfo; + } u; +}; + VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) { reshade::log::message(reshade::log::level::info, "Redirecting vkCreateInstance(pCreateInfo = %p, pAllocator = %p, pInstance = %p) ...", pCreateInfo, pAllocator, pInstance); @@ -23,22 +39,6 @@ VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, co assert(pCreateInfo != nullptr && pInstance != nullptr); // Look for layer link info if installed as a layer (provided by the Vulkan loader) - struct VkLayerInstanceLink - { - VkLayerInstanceLink *pNext; - PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr; - PFN_vkGetInstanceProcAddr pfnNextGetPhysicalDeviceProcAddr; - }; - struct VkLayerInstanceCreateInfo - { - VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO - const void *pNext; - VkLayerFunction function; - union { - VkLayerInstanceLink *pLayerInfo; - } u; - }; - const auto link_info = find_layer_info(pCreateInfo->pNext, VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO, VK_LAYER_LINK_INFO); // Get trampoline function pointers @@ -123,10 +123,10 @@ VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, co enabled_extensions.push_back(pCreateInfo->ppEnabledExtensionNames[i]); { - uint32_t num_extensions = 0; - enum_instance_extensions(nullptr, &num_extensions, nullptr); - std::vector extensions(num_extensions); - enum_instance_extensions(nullptr, &num_extensions, extensions.data()); + uint32_t num_instance_extensions = 0; + enum_instance_extensions(nullptr, &num_instance_extensions, nullptr); + std::vector extensions(num_instance_extensions); + enum_instance_extensions(nullptr, &num_instance_extensions, extensions.data()); // Make sure the driver actually supports the requested extensions const auto add_extension = [&extensions, &enabled_extensions](const char *name, bool required) { diff --git a/source/vulkan/vulkan_hooks_swapchain.cpp b/source/vulkan/vulkan_hooks_swapchain.cpp index 93446343e5..96da1efe4f 100644 --- a/source/vulkan/vulkan_hooks_swapchain.cpp +++ b/source/vulkan/vulkan_hooks_swapchain.cpp @@ -67,7 +67,6 @@ VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreat std::sort(format_list.begin(), format_list.end()); format_list.erase(std::unique(format_list.begin(), format_list.end()), format_list.end()); - // This is evil, because writing into application memory, but eh =) const_cast(existing_format_list_info)->viewFormatCount = static_cast(format_list.size()); const_cast(existing_format_list_info)->pViewFormats = format_list.data(); } @@ -257,13 +256,15 @@ VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreat if (desc.sync_interval == 0) create_info.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - // Remove format list info if format was overriden + // Remove format list info if format was overridden if (const auto existing_format_list_info = find_in_structure_chain( create_info.pNext, VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO)) { - if (std::find(existing_format_list_info->pViewFormats, existing_format_list_info->pViewFormats + existing_format_list_info->viewFormatCount, create_info.imageFormat) == (existing_format_list_info->pViewFormats + existing_format_list_info->viewFormatCount)) - // This is evil, because potentially writing into application memory, but it is what it is + if (const VkFormat *const formats_begin = existing_format_list_info->pViewFormats, *const formats_end = existing_format_list_info->pViewFormats + existing_format_list_info->viewFormatCount; + std::find(formats_begin, formats_end, create_info.imageFormat) == formats_end) + { const_cast(existing_format_list_info)->viewFormatCount = 0; + } } } #endif diff --git a/source/vulkan/vulkan_impl_command_list.cpp b/source/vulkan/vulkan_impl_command_list.cpp index 3281ff4322..a89cb296a2 100644 --- a/source/vulkan/vulkan_impl_command_list.cpp +++ b/source/vulkan/vulkan_impl_command_list.cpp @@ -614,7 +614,7 @@ void reshade::vulkan::command_list_impl::push_descriptors(api::shader_stage stag #endif } } -void reshade::vulkan::command_list_impl::bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) +void reshade::vulkan::command_list_impl::bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) { if ((stages & api::shader_stage::all_compute) != 0) { @@ -622,7 +622,7 @@ void reshade::vulkan::command_list_impl::bind_descriptor_tables(api::shader_stag _orig, VK_PIPELINE_BIND_POINT_COMPUTE, (VkPipelineLayout)layout.handle, - first, count, reinterpret_cast(tables), 0, nullptr); + first, count, reinterpret_cast(tables), dynamic_offset_count, dynamic_offsets); } if ((stages & api::shader_stage::all_graphics) != 0) { @@ -630,7 +630,7 @@ void reshade::vulkan::command_list_impl::bind_descriptor_tables(api::shader_stag _orig, VK_PIPELINE_BIND_POINT_GRAPHICS, (VkPipelineLayout)layout.handle, - first, count, reinterpret_cast(tables), 0, nullptr); + first, count, reinterpret_cast(tables), dynamic_offset_count, dynamic_offsets); } if ((stages & api::shader_stage::all_ray_tracing) != 0) { @@ -639,7 +639,7 @@ void reshade::vulkan::command_list_impl::bind_descriptor_tables(api::shader_stag _orig, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, (VkPipelineLayout)layout.handle, - first, count, reinterpret_cast(tables), 0, nullptr); + first, count, reinterpret_cast(tables), dynamic_offset_count, dynamic_offsets); #else assert(false); #endif diff --git a/source/vulkan/vulkan_impl_command_list.hpp b/source/vulkan/vulkan_impl_command_list.hpp index bb5cf4584e..0b923112be 100644 --- a/source/vulkan/vulkan_impl_command_list.hpp +++ b/source/vulkan/vulkan_impl_command_list.hpp @@ -31,7 +31,7 @@ namespace reshade::vulkan void push_constants(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values) final; void push_descriptors(api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update) override; - void bind_descriptor_tables(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables) final; + void bind_descriptor_tables2(api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables, uint32_t dynamic_offset_count, const uint32_t *dynamic_offsets) final; void bind_index_buffer(api::resource buffer, uint64_t offset, uint32_t index_size) final; void bind_vertex_buffers(uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides) final; diff --git a/source/vulkan/vulkan_impl_command_list_immediate.cpp b/source/vulkan/vulkan_impl_command_list_immediate.cpp index 5034a39a82..62ee909269 100644 --- a/source/vulkan/vulkan_impl_command_list_immediate.cpp +++ b/source/vulkan/vulkan_impl_command_list_immediate.cpp @@ -180,13 +180,12 @@ void reshade::vulkan::command_list_immediate_impl::push_descriptors(api::shader_ break; case api::descriptor_type::constant_buffer: case api::descriptor_type::shader_storage_buffer: + case api::descriptor_type::constant_buffer_with_dynamic_offset: + case api::descriptor_type::shader_storage_buffer_with_dynamic_offset: write.pBufferInfo = reinterpret_cast(update.descriptors); break; default: - if (write.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || write.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) - write.pBufferInfo = reinterpret_cast(update.descriptors); - else - assert(false); + assert(false); break; } diff --git a/source/vulkan/vulkan_impl_command_queue.cpp b/source/vulkan/vulkan_impl_command_queue.cpp index 2cb525e118..a83855364d 100644 --- a/source/vulkan/vulkan_impl_command_queue.cpp +++ b/source/vulkan/vulkan_impl_command_queue.cpp @@ -33,7 +33,7 @@ reshade::vulkan::command_queue_impl::command_queue_impl(device_impl *device, uin } // Always create queue synchronization semaphores, even for compute queues, e.g. for present from compute - for (int i = 0; i < std::size(_signal_semaphores); ++i) + for (unsigned int i = 0; i < std::size(_signal_semaphores); ++i) { VkSemaphoreCreateInfo sem_create_info { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; diff --git a/source/vulkan/vulkan_impl_device.cpp b/source/vulkan/vulkan_impl_device.cpp index 88e1e0d238..2995061fc8 100644 --- a/source/vulkan/vulkan_impl_device.cpp +++ b/source/vulkan/vulkan_impl_device.cpp @@ -1238,54 +1238,162 @@ void reshade::vulkan::device_impl::update_texture_region(const api::subresource_ destroy_resource(intermediate); } -bool reshade::vulkan::device_impl::create_shader_module(VkShaderStageFlagBits stage, const api::shader_desc &desc, VkPipelineShaderStageCreateInfo &stage_info, VkSpecializationInfo &spec_info, std::vector &spec_map) +struct pnext_link_restore { - spec_map.reserve(desc.spec_constants); - for (uint32_t i = 0; i < desc.spec_constants; ++i) - spec_map.push_back(VkSpecializationMapEntry { desc.spec_constant_ids[i], i * 4, sizeof(uint32_t) }); + VkBaseOutStructure *structure; + VkBaseOutStructure *pNext; +}; - spec_info.mapEntryCount = desc.spec_constants; - spec_info.pMapEntries = spec_map.data(); - spec_info.dataSize = desc.spec_constants * sizeof(uint32_t); - spec_info.pData = desc.spec_constant_values; +template +static void append_to_structure_chain(const void *&chain, T *node, std::vector *restore_links = nullptr) +{ + node->pNext = nullptr; + + if (chain == nullptr) + { + chain = node; + return; + } + + auto *tail = const_cast(reinterpret_cast(chain)); + while (tail->pNext != nullptr) + tail = tail->pNext; + + if (restore_links != nullptr) + restore_links->push_back({ tail, tail->pNext }); + + tail->pNext = reinterpret_cast(node); +} + +template +static bool replace_in_structure_chain(const void *&chain, const T *original_node, T *replacement_node, std::vector *restore_links = nullptr) +{ + replacement_node->pNext = original_node->pNext; + + if (chain == original_node) + { + chain = replacement_node; + return true; + } + + auto *current = const_cast(reinterpret_cast(chain)); + while (current != nullptr && current->pNext != nullptr) + { + if (current->pNext == reinterpret_cast(const_cast(original_node))) + { + if (restore_links != nullptr) + restore_links->push_back({ current, current->pNext }); + + current->pNext = reinterpret_cast(replacement_node); + return true; + } + + current = current->pNext; + } - stage_info = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; + return false; +} + +static void restore_pnext_links(const std::vector &restore_links) +{ + for (const pnext_link_restore &restore : restore_links) + restore.structure->pNext = restore.pNext; +} + +template +static T &replace_or_append_structure_chain_node(const void *&chain, VkStructureType type, T &node, std::vector &restore_links) +{ + if (const auto original_node = find_in_structure_chain(chain, type)) + { + node = *original_node; + replace_in_structure_chain(chain, original_node, &node, &restore_links); + } + else + { + node = { type }; + append_to_structure_chain(chain, &node, &restore_links); + } + + return node; +} + +static bool setup_shader_stage_inline(VkShaderStageFlagBits stage, const reshade::api::shader_desc &desc, const VkPipelineShaderStageCreateInfo *orig_stage_info, VkPipelineShaderStageCreateInfo &stage_info, VkShaderModuleCreateInfo &module_info, VkSpecializationInfo &spec_info, std::vector &spec_map, std::vector &restore_links) +{ + if (desc.code_size == 0 || desc.code == nullptr) + return false; + + stage_info = orig_stage_info != nullptr ? *orig_stage_info : VkPipelineShaderStageCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO }; stage_info.stage = stage; - stage_info.pName = desc.entry_point != nullptr ? desc.entry_point : "main"; - stage_info.pSpecializationInfo = &spec_info; + stage_info.module = VK_NULL_HANDLE; + + if (desc.entry_point != nullptr) + stage_info.pName = desc.entry_point; + else if (stage_info.pName == nullptr) + stage_info.pName = "main"; + + if (desc.spec_constants != 0) + { + spec_map.reserve(desc.spec_constants); + for (uint32_t i = 0; i < desc.spec_constants; ++i) + spec_map.push_back(VkSpecializationMapEntry { desc.spec_constant_ids[i], i * 4, sizeof(uint32_t) }); + + spec_info.mapEntryCount = desc.spec_constants; + spec_info.pMapEntries = spec_map.data(); + spec_info.dataSize = desc.spec_constants * sizeof(uint32_t); + spec_info.pData = desc.spec_constant_values; - VkShaderModuleCreateInfo create_info { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO }; - create_info.codeSize = desc.code_size; - create_info.pCode = static_cast(desc.code); + stage_info.pSpecializationInfo = &spec_info; + } + + replace_or_append_structure_chain_node(stage_info.pNext, VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, module_info, restore_links); + module_info.codeSize = desc.code_size; + module_info.pCode = static_cast(desc.code); - return vk.CreateShaderModule(_orig, &create_info, nullptr, &stage_info.module) == VK_SUCCESS; + return true; } bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline) { - VkRenderPass render_pass = VK_NULL_HANDLE; - std::vector shaders; + bool ray_tracing_pipeline = false; + bool compute_pipeline = false; - api::shader_desc vs_desc = {}; - api::shader_desc hs_desc = {}; - api::shader_desc ds_desc = {}; - api::shader_desc gs_desc = {}; - api::shader_desc ps_desc = {}; - api::shader_desc cs_desc = {}; - api::shader_desc as_desc = {}; - api::shader_desc ms_desc = {}; - api::pipeline_subobject input_layout_desc = {}; - api::stream_output_desc stream_output_desc = {}; - api::blend_desc blend_desc = {}; - api::rasterizer_desc rasterizer_desc = {}; - api::depth_stencil_desc depth_stencil_desc = {}; - api::primitive_topology topology = api::primitive_topology::undefined; - api::format depth_stencil_format = api::format::unknown; - api::pipeline_subobject render_target_formats = {}; - api::pipeline_subobject dynamic_states_subobject = {}; - uint32_t sample_mask = UINT32_MAX; - uint32_t sample_count = 1; - uint32_t viewport_count = 1; + for (uint32_t i = 0; i < subobject_count; ++i) + { + if (subobjects[i].count == 0) + continue; + + switch (subobjects[i].type) + { + case api::pipeline_subobject_type::compute_shader: + compute_pipeline = true; + break; + case api::pipeline_subobject_type::raygen_shader: + case api::pipeline_subobject_type::any_hit_shader: + case api::pipeline_subobject_type::closest_hit_shader: + case api::pipeline_subobject_type::miss_shader: + case api::pipeline_subobject_type::intersection_shader: + case api::pipeline_subobject_type::callable_shader: + case api::pipeline_subobject_type::shader_groups: + ray_tracing_pipeline = true; + break; + } + } + + if (ray_tracing_pipeline) + { + return create_pipeline(layout, subobject_count, subobjects, out_pipeline, static_cast(nullptr)); + } + else if (compute_pipeline) + { + return create_pipeline(layout, subobject_count, subobjects, out_pipeline, static_cast(nullptr)); + } + else + { + return create_pipeline(layout, subobject_count, subobjects, out_pipeline, static_cast(nullptr)); + } +} +bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline, const VkRayTracingPipelineCreateInfoKHR *orig_create_info) +{ std::vector raygen_desc; std::vector any_hit_desc; std::vector closest_hit_desc; @@ -1306,87 +1414,6 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, switch (subobjects[i].type) { - case api::pipeline_subobject_type::vertex_shader: - assert(subobjects[i].count == 1); - vs_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::hull_shader: - assert(subobjects[i].count == 1); - hs_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::domain_shader: - assert(subobjects[i].count == 1); - ds_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::geometry_shader: - assert(subobjects[i].count == 1); - gs_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::pixel_shader: - assert(subobjects[i].count == 1); - ps_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::compute_shader: - assert(subobjects[i].count == 1); - cs_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::input_layout: - input_layout_desc = subobjects[i]; - break; - case api::pipeline_subobject_type::stream_output_state: - assert(subobjects[i].count == 1); - stream_output_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::blend_state: - assert(subobjects[i].count == 1); - blend_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::rasterizer_state: - assert(subobjects[i].count == 1); - rasterizer_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::depth_stencil_state: - assert(subobjects[i].count == 1); - depth_stencil_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::primitive_topology: - assert(subobjects[i].count == 1); - topology = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::depth_stencil_format: - assert(subobjects[i].count == 1); - depth_stencil_format = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::render_target_formats: - assert(subobjects[i].count <= 8); - render_target_formats = subobjects[i]; - break; - case api::pipeline_subobject_type::sample_mask: - assert(subobjects[i].count == 1); - sample_mask = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::sample_count: - assert(subobjects[i].count == 1); - sample_count = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::viewport_count: - assert(subobjects[i].count == 1); - viewport_count = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::dynamic_pipeline_states: - dynamic_states_subobject = subobjects[i]; - break; - case api::pipeline_subobject_type::max_vertex_count: - assert(subobjects[i].count == 1); - break; // Ignored - case api::pipeline_subobject_type::amplification_shader: - assert(subobjects[i].count == 1); - as_desc = *static_cast(subobjects[i].data); - break; - case api::pipeline_subobject_type::mesh_shader: - assert(subobjects[i].count == 1); - ms_desc = *static_cast(subobjects[i].data); - break; case api::pipeline_subobject_type::raygen_shader: for (uint32_t k = 0; k < subobjects[i].count; ++k) raygen_desc.push_back(static_cast(subobjects[i].data)[k]); @@ -1441,57 +1468,59 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, } } - if (!raygen_desc.empty() || !shader_groups.empty()) - { #if VK_KHR_ray_tracing_pipeline && VK_KHR_pipeline_library - VkRayTracingPipelineCreateInfoKHR create_info { VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR }; - create_info.flags = convert_pipeline_flags(flags); + { + VkRayTracingPipelineCreateInfoKHR create_info = orig_create_info != nullptr ? *orig_create_info : VkRayTracingPipelineCreateInfoKHR { VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR }; create_info.layout = (VkPipelineLayout)layout.handle; create_info.maxPipelineRayRecursionDepth = max_recursion_depth; + if (find_in_structure_chain(create_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO) == nullptr) + create_info.flags = convert_pipeline_flags(flags); + const size_t max_shader_stage_count = raygen_desc.size() + any_hit_desc.size() + closest_hit_desc.size() + miss_desc.size() + intersection_desc.size() + callable_desc.size(); std::vector shader_stage_info; + std::vector shader_module_info; std::vector spec_info; std::vector> spec_map; + std::vector pnext_restore_links; shader_stage_info.reserve(max_shader_stage_count); + shader_module_info.reserve(max_shader_stage_count); spec_info.reserve(max_shader_stage_count); spec_map.reserve(max_shader_stage_count); + const auto append_stage = [&](VkShaderStageFlagBits stage, const api::shader_desc &shader_desc) { + return setup_shader_stage_inline(stage, shader_desc, nullptr, shader_stage_info.emplace_back(), shader_module_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back(), pnext_restore_links); + }; + for (const api::shader_desc &shader_desc : raygen_desc) { - if (!create_shader_module(VK_SHADER_STAGE_RAYGEN_BIT_KHR, shader_desc, shader_stage_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back())) + if (!append_stage(VK_SHADER_STAGE_RAYGEN_BIT_KHR, shader_desc)) goto exit_failure; - shaders.push_back(shader_stage_info.back().module); } for (const api::shader_desc &shader_desc : any_hit_desc) { - if (!create_shader_module(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, shader_desc, shader_stage_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back())) + if (!append_stage(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, shader_desc)) goto exit_failure; - shaders.push_back(shader_stage_info.back().module); } for (const api::shader_desc &shader_desc : closest_hit_desc) { - if (!create_shader_module(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, shader_desc, shader_stage_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back())) + if (!append_stage(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, shader_desc)) goto exit_failure; - shaders.push_back(shader_stage_info.back().module); } for (const api::shader_desc &shader_desc : miss_desc) { - if (!create_shader_module(VK_SHADER_STAGE_MISS_BIT_KHR, shader_desc, shader_stage_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back())) + if (!append_stage(VK_SHADER_STAGE_MISS_BIT_KHR, shader_desc)) goto exit_failure; - shaders.push_back(shader_stage_info.back().module); } for (const api::shader_desc &shader_desc : intersection_desc) { - if (!create_shader_module(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, shader_desc, shader_stage_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back())) + if (!append_stage(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, shader_desc)) goto exit_failure; - shaders.push_back(shader_stage_info.back().module); } for (const api::shader_desc &shader_desc : callable_desc) { - if (!create_shader_module(VK_SHADER_STAGE_CALLABLE_BIT_KHR, shader_desc, shader_stage_info.emplace_back(), spec_info.emplace_back(), spec_map.emplace_back())) + if (!append_stage(VK_SHADER_STAGE_CALLABLE_BIT_KHR, shader_desc)) goto exit_failure; - shaders.push_back(shader_stage_info.back().module); } create_info.stageCount = static_cast(shader_stage_info.size()); @@ -1586,124 +1615,340 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, } } - create_info.groupCount = static_cast(group_infos.size()); - create_info.pGroups = group_infos.data(); + create_info.groupCount = static_cast(group_infos.size()); + create_info.pGroups = group_infos.data(); + + if (!any_null_any_hit) + create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR; + if (!any_null_closest_hit) + create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR; + if (!any_null_miss) + create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR; + if (!any_null_intersection) + create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR; + + VkPipelineLibraryCreateInfoKHR library_info; + VkRayTracingPipelineInterfaceCreateInfoKHR interface_info; + if (!libraries.empty()) + { + library_info = { VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR }; + library_info.libraryCount = static_cast(libraries.size()); + library_info.pLibraries = reinterpret_cast(libraries.data()); + + interface_info = { VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR }; + interface_info.maxPipelineRayPayloadSize = max_payload_size; + interface_info.maxPipelineRayHitAttributeSize = max_attribute_size; + + create_info.pLibraryInfo = &library_info; + create_info.pLibraryInterface = &interface_info; + } + + if (VkPipeline object = VK_NULL_HANDLE; + vk.CreateRayTracingPipelinesKHR(_orig, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &create_info, nullptr, &object) == VK_SUCCESS) + { + *out_pipeline = { (uint64_t)object }; + return true; + } + } +#endif + +exit_failure: + *out_pipeline = { 0 }; + return false; +} +bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline, const VkComputePipelineCreateInfo *orig_create_info) +{ + api::shader_desc cs_desc = {}; + api::pipeline_flags flags = api::pipeline_flags::none; + std::vector pnext_restore_links; + + for (uint32_t i = 0; i < subobject_count; ++i) + { + if (subobjects[i].count == 0) + continue; + + switch (subobjects[i].type) + { + case api::pipeline_subobject_type::compute_shader: + assert(subobjects[i].count == 1); + cs_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::flags: + assert(subobjects[i].count == 1); + flags = *static_cast(subobjects[i].data); + break; + default: + assert(false); + goto exit_failure; + } + } + + { + VkComputePipelineCreateInfo create_info = orig_create_info != nullptr ? *orig_create_info : VkComputePipelineCreateInfo { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + create_info.layout = (VkPipelineLayout)layout.handle; + + if (find_in_structure_chain(create_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO) == nullptr) + create_info.flags = convert_pipeline_flags(flags); + + VkSpecializationInfo spec_info; + std::vector spec_map; + VkShaderModuleCreateInfo shader_module_info; + if (cs_desc.code_size != 0) + { + if (!setup_shader_stage_inline(VK_SHADER_STAGE_COMPUTE_BIT, cs_desc, orig_create_info != nullptr ? &orig_create_info->stage : nullptr, create_info.stage, shader_module_info, spec_info, spec_map, pnext_restore_links)) + goto exit_failure; + } + + if (VkPipeline object = VK_NULL_HANDLE; + vk.CreateComputePipelines(_orig, VK_NULL_HANDLE, 1, &create_info, nullptr, &object) == VK_SUCCESS) + { + restore_pnext_links(pnext_restore_links); + *out_pipeline = { (uint64_t)object }; + return true; + } + } + +exit_failure: + restore_pnext_links(pnext_restore_links); + *out_pipeline = { 0 }; + return false; +} +bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline, const VkGraphicsPipelineCreateInfo *orig_create_info) +{ + VkRenderPass render_pass = VK_NULL_HANDLE; + + api::shader_desc vs_desc = {}; + api::shader_desc hs_desc = {}; + api::shader_desc ds_desc = {}; + api::shader_desc gs_desc = {}; + api::shader_desc ps_desc = {}; + api::shader_desc as_desc = {}; + api::shader_desc ms_desc = {}; + api::pipeline_subobject input_layout_desc = {}; + api::stream_output_desc stream_output_desc = {}; + api::blend_desc blend_desc = {}; + api::rasterizer_desc rasterizer_desc = {}; + api::depth_stencil_desc depth_stencil_desc = {}; + api::primitive_topology topology = api::primitive_topology::undefined; + api::format depth_stencil_format = api::format::unknown; + api::pipeline_subobject render_target_formats = {}; + api::pipeline_subobject dynamic_states_subobject = {}; + uint32_t sample_mask = UINT32_MAX; + uint32_t sample_count = 1; + uint32_t viewport_count = 1; + std::vector libraries; + api::pipeline_flags flags = api::pipeline_flags::none; + std::vector pnext_restore_links; + + for (uint32_t i = 0; i < subobject_count; ++i) + { + if (subobjects[i].count == 0) + continue; + + switch (subobjects[i].type) + { + case api::pipeline_subobject_type::vertex_shader: + assert(subobjects[i].count == 1); + vs_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::hull_shader: + assert(subobjects[i].count == 1); + hs_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::domain_shader: + assert(subobjects[i].count == 1); + ds_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::geometry_shader: + assert(subobjects[i].count == 1); + gs_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::pixel_shader: + assert(subobjects[i].count == 1); + ps_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::input_layout: + input_layout_desc = subobjects[i]; + break; + case api::pipeline_subobject_type::stream_output_state: + assert(subobjects[i].count == 1); + stream_output_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::blend_state: + assert(subobjects[i].count == 1); + blend_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::rasterizer_state: + assert(subobjects[i].count == 1); + rasterizer_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::depth_stencil_state: + assert(subobjects[i].count == 1); + depth_stencil_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::primitive_topology: + assert(subobjects[i].count == 1); + topology = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::depth_stencil_format: + assert(subobjects[i].count == 1); + depth_stencil_format = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::render_target_formats: + assert(subobjects[i].count <= 8); + render_target_formats = subobjects[i]; + break; + case api::pipeline_subobject_type::sample_mask: + assert(subobjects[i].count == 1); + sample_mask = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::sample_count: + assert(subobjects[i].count == 1); + sample_count = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::viewport_count: + assert(subobjects[i].count == 1); + viewport_count = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::dynamic_pipeline_states: + dynamic_states_subobject = subobjects[i]; + break; + case api::pipeline_subobject_type::max_vertex_count: + assert(subobjects[i].count == 1); + break; // Ignored + case api::pipeline_subobject_type::amplification_shader: + assert(subobjects[i].count == 1); + as_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::mesh_shader: + assert(subobjects[i].count == 1); + ms_desc = *static_cast(subobjects[i].data); + break; + case api::pipeline_subobject_type::libraries: + for (uint32_t k = 0; k < subobjects[i].count; ++k) + libraries.push_back(static_cast(subobjects[i].data)[k]); + break; + case api::pipeline_subobject_type::flags: + assert(subobjects[i].count == 1); + flags = *static_cast(subobjects[i].data); + break; + default: + assert(false); + goto exit_failure; + } + } + + { + VkGraphicsPipelineCreateInfo create_info = orig_create_info != nullptr ? *orig_create_info : VkGraphicsPipelineCreateInfo { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; + create_info.layout = (VkPipelineLayout)layout.handle; - if (!any_null_any_hit) - create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR; - if (!any_null_closest_hit) - create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR; - if (!any_null_miss) - create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR; - if (!any_null_intersection) - create_info.flags |= VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR; + if (find_in_structure_chain(create_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO) == nullptr) + create_info.flags = convert_pipeline_flags(flags); - VkPipelineLibraryCreateInfoKHR library_info; - VkRayTracingPipelineInterfaceCreateInfoKHR interface_info; - if (!libraries.empty()) - { - library_info = { VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR }; - library_info.libraryCount = static_cast(libraries.size()); - library_info.pLibraries = reinterpret_cast(libraries.data()); + VkPipelineShaderStageCreateInfo shader_stage_info[6]; + create_info.stageCount = 0; + create_info.pStages = shader_stage_info; - interface_info = { VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR }; - interface_info.maxPipelineRayPayloadSize = max_payload_size; - interface_info.maxPipelineRayHitAttributeSize = max_attribute_size; + VkSpecializationInfo spec_info[6]; + std::vector spec_map[6]; + VkShaderModuleCreateInfo shader_module_info[6]; - create_info.pLibraryInfo = &library_info; - create_info.pLibraryInterface = &interface_info; - } + const auto append_stage = [&](VkShaderStageFlagBits stage, const api::shader_desc &shader_desc, const VkPipelineShaderStageCreateInfo *original_stage_info) { + if (shader_desc.code_size != 0) + { + if (!setup_shader_stage_inline(stage, shader_desc, original_stage_info, shader_stage_info[create_info.stageCount], shader_module_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount], pnext_restore_links)) + return false; + ++create_info.stageCount; + } + else if (original_stage_info != nullptr) + { + shader_stage_info[create_info.stageCount++] = *original_stage_info; + } + return true; + }; - if (VkPipeline object = VK_NULL_HANDLE; - vk.CreateRayTracingPipelinesKHR(_orig, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &create_info, nullptr, &object) == VK_SUCCESS) + if (orig_create_info != nullptr) { - for (const VkShaderModule shader : shaders) - vk.DestroyShaderModule(_orig, shader, nullptr); - - *out_pipeline = { (uint64_t)object }; - return true; - } + const auto get_shader_desc = [&](VkShaderStageFlagBits stage) -> const api::shader_desc * { + switch (stage) + { + case VK_SHADER_STAGE_VERTEX_BIT: + return &vs_desc; + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + return &hs_desc; + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + return &ds_desc; + case VK_SHADER_STAGE_GEOMETRY_BIT: + return &gs_desc; + case VK_SHADER_STAGE_FRAGMENT_BIT: + return &ps_desc; +#if VK_EXT_mesh_shader + case VK_SHADER_STAGE_TASK_BIT_EXT: + return &as_desc; + case VK_SHADER_STAGE_MESH_BIT_EXT: + return &ms_desc; #endif - } - else if (cs_desc.code_size != 0) - { - VkComputePipelineCreateInfo create_info { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; - create_info.flags = convert_pipeline_flags(flags); - create_info.layout = (VkPipelineLayout)layout.handle; + default: + return nullptr; + } + }; - VkSpecializationInfo spec_info; - std::vector spec_map; - if (cs_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_COMPUTE_BIT, cs_desc, create_info.stage, spec_info, spec_map)) - goto exit_failure; - shaders.push_back(create_info.stage.module); - } + VkShaderStageFlags present_stages = 0; - if (VkPipeline object = VK_NULL_HANDLE; - vk.CreateComputePipelines(_orig, VK_NULL_HANDLE, 1, &create_info, nullptr, &object) == VK_SUCCESS) - { - vk.DestroyShaderModule(_orig, create_info.stage.module, nullptr); + for (uint32_t i = 0; i < orig_create_info->stageCount; ++i) + { + const VkPipelineShaderStageCreateInfo &orig_stage_info = orig_create_info->pStages[i]; - *out_pipeline = { (uint64_t)object }; - return true; - } - } - else - { - VkGraphicsPipelineCreateInfo create_info { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO }; - create_info.flags = convert_pipeline_flags(flags); - create_info.layout = (VkPipelineLayout)layout.handle; + if (const api::shader_desc *shader_desc = get_shader_desc(orig_stage_info.stage)) + { + present_stages |= orig_stage_info.stage; - VkPipelineShaderStageCreateInfo shader_stage_info[6]; - create_info.pStages = shader_stage_info; + if (!append_stage(orig_stage_info.stage, *shader_desc, &orig_stage_info)) + goto exit_failure; + } + else + { + shader_stage_info[create_info.stageCount++] = orig_stage_info; + } + } - VkSpecializationInfo spec_info[6]; - std::vector spec_map[6]; - if (vs_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_VERTEX_BIT, vs_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + // Add new added stages from addon + if ((present_stages & VK_SHADER_STAGE_VERTEX_BIT) == 0 && vs_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_VERTEX_BIT, vs_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); - } - if (hs_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, hs_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + if ((present_stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) == 0 && hs_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, hs_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); - } - if (ds_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, ds_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + if ((present_stages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) == 0 && ds_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, ds_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); - } - if (gs_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_GEOMETRY_BIT, gs_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + if ((present_stages & VK_SHADER_STAGE_GEOMETRY_BIT) == 0 && gs_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_GEOMETRY_BIT, gs_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); - } - if (ps_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_FRAGMENT_BIT, ps_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + if ((present_stages & VK_SHADER_STAGE_FRAGMENT_BIT) == 0 && ps_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_FRAGMENT_BIT, ps_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); - } #if VK_EXT_mesh_shader - if (as_desc.code_size != 0) - { - if (!create_shader_module(VK_SHADER_STAGE_TASK_BIT_EXT, as_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + if ((present_stages & VK_SHADER_STAGE_TASK_BIT_EXT) == 0 && as_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_TASK_BIT_EXT, as_desc, nullptr)) + goto exit_failure; + if ((present_stages & VK_SHADER_STAGE_MESH_BIT_EXT) == 0 && ms_desc.code_size != 0 && !append_stage(VK_SHADER_STAGE_MESH_BIT_EXT, ms_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); +#endif } - if (ms_desc.code_size != 0) + else { - if (!create_shader_module(VK_SHADER_STAGE_MESH_BIT_EXT, ms_desc, shader_stage_info[create_info.stageCount], spec_info[create_info.stageCount], spec_map[create_info.stageCount])) + if (!append_stage(VK_SHADER_STAGE_VERTEX_BIT, vs_desc, nullptr)) + goto exit_failure; + if (!append_stage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, hs_desc, nullptr)) + goto exit_failure; + if (!append_stage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, ds_desc, nullptr)) + goto exit_failure; + if (!append_stage(VK_SHADER_STAGE_GEOMETRY_BIT, gs_desc, nullptr)) + goto exit_failure; + if (!append_stage(VK_SHADER_STAGE_FRAGMENT_BIT, ps_desc, nullptr)) + goto exit_failure; +#if VK_EXT_mesh_shader + if (!append_stage(VK_SHADER_STAGE_TASK_BIT_EXT, as_desc, nullptr)) + goto exit_failure; + if (!append_stage(VK_SHADER_STAGE_MESH_BIT_EXT, ms_desc, nullptr)) goto exit_failure; - shaders.push_back(shader_stage_info[create_info.stageCount++].module); - } #endif + } std::vector dynamic_states; // Always make scissor rectangles and viewports dynamic @@ -1711,7 +1956,7 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); convert_dynamic_states(dynamic_states_subobject.count, static_cast(dynamic_states_subobject.data), dynamic_states); - VkPipelineDynamicStateCreateInfo dynamic_state_info { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + VkPipelineDynamicStateCreateInfo dynamic_state_info = create_info.pDynamicState != nullptr ? *create_info.pDynamicState : VkPipelineDynamicStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; create_info.pDynamicState = &dynamic_state_info; dynamic_state_info.dynamicStateCount = static_cast(dynamic_states.size()); dynamic_state_info.pDynamicStates = dynamic_states.data(); @@ -1719,50 +1964,53 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, std::vector vertex_bindings; std::vector vertex_attributes; std::vector vertex_binding_divisors; + convert_input_layout_desc(input_layout_desc.count, static_cast(input_layout_desc.data), vertex_bindings, vertex_attributes, vertex_binding_divisors); - VkPipelineVertexInputDivisorStateCreateInfo vertex_input_divisor_state_info { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO }; - vertex_input_divisor_state_info.vertexBindingDivisorCount = static_cast(vertex_binding_divisors.size()); - vertex_input_divisor_state_info.pVertexBindingDivisors = vertex_binding_divisors.data(); + VkPipelineVertexInputDivisorStateCreateInfo vertex_input_divisor_state_info; - VkPipelineVertexInputStateCreateInfo vertex_input_state_info { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + VkPipelineVertexInputStateCreateInfo vertex_input_state_info = create_info.pVertexInputState != nullptr ? *create_info.pVertexInputState : VkPipelineVertexInputStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; create_info.pVertexInputState = &vertex_input_state_info; if (!vertex_binding_divisors.empty()) - vertex_input_state_info.pNext = &vertex_input_divisor_state_info; + { + replace_or_append_structure_chain_node(vertex_input_state_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO, vertex_input_divisor_state_info, pnext_restore_links); + vertex_input_divisor_state_info.vertexBindingDivisorCount = static_cast(vertex_binding_divisors.size()); + vertex_input_divisor_state_info.pVertexBindingDivisors = vertex_binding_divisors.data(); + } vertex_input_state_info.vertexBindingDescriptionCount = static_cast(vertex_bindings.size()); vertex_input_state_info.pVertexBindingDescriptions = vertex_bindings.data(); vertex_input_state_info.vertexAttributeDescriptionCount = static_cast(vertex_attributes.size()); vertex_input_state_info.pVertexAttributeDescriptions = vertex_attributes.data(); - VkPipelineInputAssemblyStateCreateInfo input_assembly_state_info { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + VkPipelineInputAssemblyStateCreateInfo input_assembly_state_info = create_info.pInputAssemblyState != nullptr ? *create_info.pInputAssemblyState : VkPipelineInputAssemblyStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; create_info.pInputAssemblyState = &input_assembly_state_info; input_assembly_state_info.primitiveRestartEnable = VK_FALSE; input_assembly_state_info.topology = convert_primitive_topology(topology); - VkPipelineTessellationStateCreateInfo tessellation_state_info { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO }; + VkPipelineTessellationStateCreateInfo tessellation_state_info = create_info.pTessellationState != nullptr ? *create_info.pTessellationState : VkPipelineTessellationStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO }; create_info.pTessellationState = &tessellation_state_info; if (input_assembly_state_info.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) tessellation_state_info.patchControlPoints = static_cast(topology) - static_cast(api::primitive_topology::patch_list_01_cp) + 1; - VkPipelineViewportStateCreateInfo viewport_state_info { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + VkPipelineViewportStateCreateInfo viewport_state_info = create_info.pViewportState != nullptr ? *create_info.pViewportState : VkPipelineViewportStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; create_info.pViewportState = &viewport_state_info; viewport_state_info.scissorCount = viewport_count; viewport_state_info.viewportCount = viewport_count; - VkPipelineRasterizationStateCreateInfo rasterization_state_info { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; - create_info.pRasterizationState = &rasterization_state_info; + VkPipelineRasterizationStateCreateInfo rasterization_state_info; + { + rasterization_state_info = create_info.pRasterizationState != nullptr ? *create_info.pRasterizationState : VkPipelineRasterizationStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + create_info.pRasterizationState = &rasterization_state_info; + } #if VK_EXT_conservative_rasterization VkPipelineRasterizationConservativeStateCreateInfoEXT conservative_rasterization_info; - if (rasterizer_desc.conservative_rasterization != 0) + if (rasterizer_desc.conservative_rasterization != 0 || find_in_structure_chain(rasterization_state_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT) != nullptr) { - if (!vk.EXT_conservative_rasterization) + if (rasterizer_desc.conservative_rasterization != 0 && !vk.EXT_conservative_rasterization) goto exit_failure; - conservative_rasterization_info = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT }; - conservative_rasterization_info.pNext = rasterization_state_info.pNext; - - rasterization_state_info.pNext = &conservative_rasterization_info; + replace_or_append_structure_chain_node(rasterization_state_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, conservative_rasterization_info, pnext_restore_links); } #endif @@ -1774,16 +2022,13 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, VkPipelineRasterizationStateStreamCreateInfoEXT stream_rasterization_info; if (stream_output_desc.rasterized_stream != 0) { - stream_rasterization_info = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT }; - stream_rasterization_info.pNext = rasterization_state_info.pNext; - - rasterization_state_info.pNext = &stream_rasterization_info; + replace_or_append_structure_chain_node(rasterization_state_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT, stream_rasterization_info, pnext_restore_links); convert_stream_output_desc(stream_output_desc, rasterization_state_info); } #endif - VkPipelineMultisampleStateCreateInfo multisample_state_info { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + VkPipelineMultisampleStateCreateInfo multisample_state_info = create_info.pMultisampleState != nullptr ? *create_info.pMultisampleState : VkPipelineMultisampleStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; create_info.pMultisampleState = &multisample_state_info; multisample_state_info.rasterizationSamples = sample_count != 0 ? static_cast(sample_count) : VK_SAMPLE_COUNT_1_BIT; multisample_state_info.sampleShadingEnable = VK_FALSE; @@ -1791,14 +2036,14 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, multisample_state_info.alphaToOneEnable = VK_FALSE; multisample_state_info.pSampleMask = &sample_mask; - VkPipelineDepthStencilStateCreateInfo depth_stencil_state_info { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; + VkPipelineDepthStencilStateCreateInfo depth_stencil_state_info = create_info.pDepthStencilState != nullptr ? *create_info.pDepthStencilState : VkPipelineDepthStencilStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; create_info.pDepthStencilState = &depth_stencil_state_info; convert_depth_stencil_desc(depth_stencil_desc, depth_stencil_state_info); depth_stencil_state_info.depthBoundsTestEnable = VK_FALSE; depth_stencil_state_info.minDepthBounds = 0.0f; depth_stencil_state_info.maxDepthBounds = 1.0f; - VkPipelineColorBlendStateCreateInfo color_blend_state_info { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + VkPipelineColorBlendStateCreateInfo color_blend_state_info = create_info.pColorBlendState != nullptr ? *create_info.pColorBlendState : VkPipelineColorBlendStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; create_info.pColorBlendState = &color_blend_state_info; color_blend_state_info.attachmentCount = 8; temp_mem attachment_info(color_blend_state_info.attachmentCount); @@ -1808,30 +2053,29 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, temp_mem attachment_formats(render_target_formats.count); color_blend_state_info.attachmentCount = 0; for (uint32_t i = 0; i < render_target_formats.count; ++i, ++color_blend_state_info.attachmentCount) - { attachment_formats[i] = convert_format(static_cast(render_target_formats.data)[i]); - assert(attachment_formats[i] != VK_FORMAT_UNDEFINED); - } #if VK_KHR_dynamic_rendering VkPipelineRenderingCreateInfo dynamic_rendering_info; - if (vk.KHR_dynamic_rendering) + if (create_info.renderPass == VK_NULL_HANDLE && vk.KHR_dynamic_rendering) { - dynamic_rendering_info = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO }; - dynamic_rendering_info.pNext = create_info.pNext; + replace_or_append_structure_chain_node(create_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, dynamic_rendering_info, pnext_restore_links); + dynamic_rendering_info.colorAttachmentCount = color_blend_state_info.attachmentCount; dynamic_rendering_info.pColorAttachmentFormats = attachment_formats.p; const VkFormat depth_stencil_format_vk = convert_format(depth_stencil_format); + dynamic_rendering_info.depthAttachmentFormat = VK_FORMAT_UNDEFINED; + dynamic_rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED; if (aspect_flags_from_format(depth_stencil_format_vk) & VK_IMAGE_ASPECT_DEPTH_BIT) dynamic_rendering_info.depthAttachmentFormat = depth_stencil_format_vk; if (aspect_flags_from_format(depth_stencil_format_vk) & VK_IMAGE_ASPECT_STENCIL_BIT) dynamic_rendering_info.stencilAttachmentFormat = depth_stencil_format_vk; - create_info.pNext = &dynamic_rendering_info; } else #endif + if (create_info.renderPass == VK_NULL_HANDLE) { const uint32_t max_attachments = color_blend_state_info.attachmentCount + 1; @@ -1900,42 +2144,39 @@ bool reshade::vulkan::device_impl::create_pipeline(api::pipeline_layout layout, goto exit_failure; create_info.renderPass = render_pass; + create_info.subpass = 0; } #if VK_KHR_pipeline_library VkPipelineLibraryCreateInfoKHR library_info; if (!libraries.empty()) { - library_info = { VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR }; - library_info.pNext = create_info.pNext; + replace_or_append_structure_chain_node(create_info.pNext, VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR, library_info, pnext_restore_links); + library_info.libraryCount = static_cast(libraries.size()); library_info.pLibraries = reinterpret_cast(libraries.data()); - - create_info.pNext = &library_info; } #endif if (VkPipeline object = VK_NULL_HANDLE; vk.CreateGraphicsPipelines(_orig, VK_NULL_HANDLE, 1, &create_info, nullptr, &object) == VK_SUCCESS) { + restore_pnext_links(pnext_restore_links); + if (render_pass != VK_NULL_HANDLE) vk.DestroyRenderPass(_orig, render_pass, nullptr); - for (const VkShaderModule shader : shaders) - vk.DestroyShaderModule(_orig, shader, nullptr); - *out_pipeline = { (uint64_t)object }; return true; } + } exit_failure: + restore_pnext_links(pnext_restore_links); if (render_pass != VK_NULL_HANDLE) vk.DestroyRenderPass(_orig, render_pass, nullptr); - for (const VkShaderModule shader : shaders) - vk.DestroyShaderModule(_orig, shader, nullptr); - *out_pipeline = { 0 }; return false; } @@ -1944,168 +2185,257 @@ void reshade::vulkan::device_impl::destroy_pipeline(api::pipeline pipeline) vk.DestroyPipeline(_orig, (VkPipeline)pipeline.handle, nullptr); } -bool reshade::vulkan::device_impl::create_pipeline_layout(uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout *out_layout) +bool reshade::vulkan::device_impl::create_descriptor_set_layout(const api::pipeline_layout_param ¶m, VkDescriptorSetLayout *out_set_layout, std::vector &embedded_samplers) { - std::vector push_constant_ranges; - std::vector set_layouts; - std::vector embedded_samplers; - set_layouts.reserve(param_count); - push_constant_ranges.reserve(param_count); - - for (uint32_t i = 0; i < param_count; ++i) + assert(param.type != api::pipeline_layout_param_type::push_constants); + + bool push_descriptors = (param.type == api::pipeline_layout_param_type::push_descriptors); + bool update_after_bind_pool = false; + const bool with_flags = (param.type == api::pipeline_layout_param_type::descriptor_table_with_flags || param.type == api::pipeline_layout_param_type::push_descriptors_with_ranges_and_flags); + const uint32_t range_count = push_descriptors ? 1 : with_flags ? param.descriptor_table_with_flags.count : param.descriptor_table.count; + const api::descriptor_range *range = push_descriptors ? ¶m.push_descriptors : with_flags ? param.descriptor_table_with_flags.ranges : param.descriptor_table.ranges; + push_descriptors |= (param.type == api::pipeline_layout_param_type::push_descriptors_with_ranges || param.type == api::pipeline_layout_param_type::push_descriptors_with_ranges_and_flags); + + object_data data; + data.num_descriptors = 0; + if (with_flags) { - if (params[i].type != api::pipeline_layout_param_type::push_constants) - { - bool push_descriptors = (params[i].type == api::pipeline_layout_param_type::push_descriptors); - bool update_after_bind_pool = false; - const bool with_flags = (params[i].type == api::pipeline_layout_param_type::descriptor_table_with_flags || params[i].type == api::pipeline_layout_param_type::push_descriptors_with_ranges_and_flags); - const uint32_t range_count = push_descriptors ? 1 : with_flags ? params[i].descriptor_table_with_flags.count : params[i].descriptor_table.count; - const api::descriptor_range *range = push_descriptors ? ¶ms[i].push_descriptors : with_flags ? params[i].descriptor_table_with_flags.ranges : params[i].descriptor_table.ranges; - 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_ranges_and_flags); + data.ranges_with_flags.reserve(range_count); + data.static_samplers.resize(range_count); + } + else + { + data.ranges.reserve(range_count); + } + data.binding_to_offset.reserve(range_count); + data.push_descriptors = push_descriptors; - object_data data; - data.ranges.reserve(range_count); - data.binding_to_offset.reserve(range_count); + std::vector internal_bindings; + std::vector internal_binding_flags; + std::vector> internal_samplers; + internal_bindings.reserve(range_count); + internal_binding_flags.reserve(range_count); + internal_samplers.reserve(range_count); - std::vector internal_bindings; - std::vector internal_binding_flags; - std::vector> internal_samplers; - internal_bindings.reserve(range_count); - internal_binding_flags.reserve(range_count); - internal_samplers.reserve(range_count); + for (uint32_t k = 0, offset = 0; k < range_count; ++k, range = (with_flags ? static_cast(range) + 1 : range + 1)) + { + if (with_flags) + data.ranges_with_flags.emplace_back(*static_cast(range)).static_samplers = nullptr; + else + data.ranges.push_back(*range); - for (uint32_t k = 0, offset = 0; k < range_count; ++k, range = (with_flags ? static_cast(range) + 1 : range + 1)) - { - data.ranges.push_back(*static_cast(range)); + if (range->count == 0) + continue; - if (range->count == 0) - continue; + const uint32_t max_binding = (range->count == UINT32_MAX) ? range->binding : range->binding + (range->count - range->array_size); + if (max_binding >= data.binding_to_offset.size()) + data.binding_to_offset.resize(max_binding + 1); + data.binding_to_offset[range->binding] = offset; - const uint32_t max_binding = (range->count == UINT32_MAX) ? range->binding : range->binding + (range->count - range->array_size); - if (max_binding >= data.binding_to_offset.size()) - data.binding_to_offset.resize(max_binding + 1); - data.binding_to_offset[range->binding] = offset; + VkDescriptorSetLayoutBinding &internal_binding = internal_bindings.emplace_back(); + internal_binding.binding = range->binding; + internal_binding.descriptorType = convert_descriptor_type(range->type); + internal_binding.descriptorCount = range->array_size; + internal_binding.stageFlags = static_cast(range->visibility); - VkDescriptorSetLayoutBinding &internal_binding = internal_bindings.emplace_back(); - internal_binding.binding = range->binding; - internal_binding.descriptorType = convert_descriptor_type(range->type); - internal_binding.descriptorCount = range->array_size; - internal_binding.stageFlags = static_cast(range->visibility); + offset += internal_binding.descriptorCount; - offset += internal_binding.descriptorCount; + if (with_flags && (range->type == api::descriptor_type::sampler || range->type == api::descriptor_type::sampler_with_resource_view) && static_cast(range)->static_samplers != nullptr) + { + if (range->array_size != 1 || range->count == UINT32_MAX) + return false; - if (with_flags && (range->type == api::descriptor_type::sampler || range->type == api::descriptor_type::sampler_with_resource_view) && static_cast(range)->static_samplers != nullptr) - { - if (range->array_size != 1 || range->count == UINT32_MAX) - goto exit_failure; + data.static_samplers[k].assign(static_cast(range)->static_samplers, static_cast(range)->static_samplers + range->count); + data.ranges_with_flags.back().static_samplers = data.static_samplers[k].data(); - std::vector &internal_binding_samplers = internal_samplers.emplace_back(); - internal_binding_samplers.resize(range->count); + std::vector &internal_binding_samplers = internal_samplers.emplace_back(); + internal_binding_samplers.resize(range->count); - for (uint32_t j = 0; j < range->count; ++j) - { - VkSamplerCreateInfo create_info { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; - // Cannot have custom border color in immutable samplers - convert_sampler_desc(static_cast(range)->static_samplers[j], create_info); + for (uint32_t j = 0; j < range->count; ++j) + { + VkSamplerCreateInfo create_info { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO }; + // Cannot have custom border color in immutable samplers + convert_sampler_desc(static_cast(range)->static_samplers[j], create_info); - if (vk.CreateSampler(_orig, &create_info, nullptr, &embedded_samplers.emplace_back()) != VK_SUCCESS) - goto exit_failure; + if (vk.CreateSampler(_orig, &create_info, nullptr, &embedded_samplers.emplace_back()) != VK_SUCCESS) + return false; - internal_binding_samplers[j] = embedded_samplers.back(); - } + internal_binding_samplers[j] = embedded_samplers.back(); + } - internal_binding.pImmutableSamplers = internal_binding_samplers.data(); - } + internal_binding.pImmutableSamplers = internal_binding_samplers.data(); + } + + data.num_descriptors += internal_binding.descriptorCount; - VkDescriptorBindingFlags binding_flags = 0; + VkDescriptorBindingFlags binding_flags = 0; #if VK_EXT_descriptor_indexing - if (with_flags && vk.EXT_descriptor_indexing) - { - binding_flags = convert_descriptor_range_flags(static_cast(range)->flags); + if (with_flags && vk.EXT_descriptor_indexing) + { + binding_flags = convert_descriptor_range_flags(static_cast(range)->flags); - if ((binding_flags & VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT) != 0) - update_after_bind_pool = true; - } + if ((binding_flags & VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT) != 0) + update_after_bind_pool = true; + } #endif - if (range->count == UINT32_MAX) - { - internal_binding_flags.push_back(binding_flags | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT); - break; // Unbounded range must be the last binding - } - else - { - internal_binding_flags.push_back(binding_flags); - } + if (range->count == UINT32_MAX) + { + internal_binding_flags.push_back(binding_flags | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT); + break; // Unbounded range must be the last binding + } + else + { + internal_binding_flags.push_back(binding_flags); + } - // Add additional bindings if the total descriptor count exceeds the array size of the binding - for (uint32_t j = 0; j < (range->count - range->array_size); ++j) - { - data.binding_to_offset[range->binding + 1 + j] = offset; + // Add additional bindings if the total descriptor count exceeds the array size of the binding + for (uint32_t j = 0; j < (range->count - range->array_size); ++j) + { + data.binding_to_offset[range->binding + 1 + j] = offset; - VkDescriptorSetLayoutBinding &additional_binding = internal_bindings.emplace_back(); - additional_binding.binding = range->binding + 1 + j; - additional_binding.descriptorType = convert_descriptor_type(range->type); - additional_binding.descriptorCount = 1; - additional_binding.stageFlags = static_cast(range->visibility); + VkDescriptorSetLayoutBinding &additional_binding = internal_bindings.emplace_back(); + additional_binding.binding = range->binding + 1 + j; + additional_binding.descriptorType = convert_descriptor_type(range->type); + additional_binding.descriptorCount = 1; + additional_binding.stageFlags = static_cast(range->visibility); - offset += additional_binding.descriptorCount; + offset += additional_binding.descriptorCount; + ++data.num_descriptors; - internal_binding_flags.push_back(binding_flags); - } - } + internal_binding_flags.push_back(binding_flags); + } + } - VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_info { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO }; - binding_flags_info.bindingCount = static_cast(internal_binding_flags.size()); - binding_flags_info.pBindingFlags = internal_binding_flags.data(); + VkDescriptorSetLayoutBindingFlagsCreateInfo binding_flags_info { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO }; + binding_flags_info.bindingCount = static_cast(internal_binding_flags.size()); + binding_flags_info.pBindingFlags = internal_binding_flags.data(); - VkDescriptorSetLayoutCreateInfo create_info { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, &binding_flags_info }; - create_info.bindingCount = static_cast(internal_bindings.size()); - create_info.pBindings = internal_bindings.data(); + VkDescriptorSetLayoutCreateInfo create_info { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, &binding_flags_info }; + create_info.bindingCount = static_cast(internal_bindings.size()); + create_info.pBindings = internal_bindings.data(); #if VK_KHR_push_descriptor - if (push_descriptors && vk.KHR_push_descriptor) - create_info.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT; + if (push_descriptors && vk.KHR_push_descriptor) + create_info.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT; #endif #if VK_EXT_descriptor_indexing - if (update_after_bind_pool && vk.EXT_descriptor_indexing) - create_info.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; + if (update_after_bind_pool && vk.EXT_descriptor_indexing) + create_info.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT; #endif - if (vk.CreateDescriptorSetLayout(_orig, &create_info, nullptr, &set_layouts.emplace_back()) == VK_SUCCESS) + if (vk.CreateDescriptorSetLayout(_orig, &create_info, nullptr, out_set_layout) == VK_SUCCESS) + { + register_object(*out_set_layout, std::move(data)); + return true; + } + + return false; +} + +bool reshade::vulkan::device_impl::create_pipeline_layout(uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout *out_layout) +{ + return create_pipeline_layout(param_count, params, out_layout, nullptr); +} +bool reshade::vulkan::device_impl::create_pipeline_layout(uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout *out_layout, const VkPipelineLayoutCreateInfo *orig_create_info) +{ + object_data layout_data; + layout_data.set_layouts.reserve(param_count); + layout_data.owned_set_layouts.reserve(param_count); + layout_data.owns_set_layouts = true; + + std::vector push_constant_ranges; + push_constant_ranges.reserve(param_count); + + for (uint32_t i = 0; i < param_count; ++i) + { + if (params[i].type == api::pipeline_layout_param_type::push_constants) + { + VkPushConstantRange &push_constant_range = push_constant_ranges.emplace_back(); + push_constant_range.stageFlags = static_cast(params[i].push_constants.visibility); + push_constant_range.offset = params[i].push_constants.binding * 4; + push_constant_range.size = params[i].push_constants.count * 4; + continue; + } + + bool reuse_orig_set_layout = false; + VkDescriptorSetLayout set_layout = VK_NULL_HANDLE; + + if (orig_create_info != nullptr && i < orig_create_info->setLayoutCount) + { + if (const VkDescriptorSetLayout orig_set_layout = orig_create_info->pSetLayouts[i]) { - register_object(set_layouts.back(), std::move(data)); + const auto orig_set_layout_data = get_private_data_for_object(orig_set_layout); + + switch (params[i].type) + { + case api::pipeline_layout_param_type::descriptor_table: + if (!orig_set_layout_data->push_descriptors && + params[i].descriptor_table.count == orig_set_layout_data->ranges.size() && + params[i].descriptor_table.ranges == orig_set_layout_data->ranges.data()) + { + set_layout = orig_set_layout; + reuse_orig_set_layout = true; + } + break; + case api::pipeline_layout_param_type::descriptor_table_with_flags: + if (!orig_set_layout_data->push_descriptors && + params[i].descriptor_table_with_flags.count == orig_set_layout_data->ranges_with_flags.size() && + params[i].descriptor_table_with_flags.ranges == orig_set_layout_data->ranges_with_flags.data()) + { + set_layout = orig_set_layout; + reuse_orig_set_layout = true; + } + break; + case api::pipeline_layout_param_type::push_descriptors_with_ranges: + if (orig_set_layout_data->push_descriptors && + params[i].descriptor_table.count == orig_set_layout_data->ranges.size() && + params[i].descriptor_table.ranges == orig_set_layout_data->ranges.data()) + { + set_layout = orig_set_layout; + reuse_orig_set_layout = true; + } + break; + case api::pipeline_layout_param_type::push_descriptors_with_ranges_and_flags: + if (orig_set_layout_data->push_descriptors && + params[i].descriptor_table_with_flags.count == orig_set_layout_data->ranges_with_flags.size() && + params[i].descriptor_table_with_flags.ranges == orig_set_layout_data->ranges_with_flags.data()) + { + set_layout = orig_set_layout; + reuse_orig_set_layout = true; + } + break; + } } - else + else if (params[i].type == api::pipeline_layout_param_type::push_descriptors && params[i].push_descriptors.count == 0) { - goto exit_failure; + set_layout = VK_NULL_HANDLE; + reuse_orig_set_layout = true; } } - else + + if (!reuse_orig_set_layout) { - VkPushConstantRange &push_constant_range = push_constant_ranges.emplace_back(); - push_constant_range.stageFlags = static_cast(params[i].push_constants.visibility); - push_constant_range.offset = params[i].push_constants.binding * 4; - push_constant_range.size = params[i].push_constants.count * 4; + if (!create_descriptor_set_layout(params[i], &set_layout, layout_data.embedded_samplers)) + goto exit_failure; + + layout_data.owned_set_layouts.push_back(set_layout); } + + layout_data.set_layouts.push_back(set_layout); } { - VkPipelineLayoutCreateInfo create_info { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; - create_info.setLayoutCount = static_cast(set_layouts.size()); - create_info.pSetLayouts = set_layouts.data(); + VkPipelineLayoutCreateInfo create_info = orig_create_info != nullptr ? *orig_create_info : VkPipelineLayoutCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + create_info.setLayoutCount = static_cast(layout_data.set_layouts.size()); + create_info.pSetLayouts = layout_data.set_layouts.data(); create_info.pushConstantRangeCount = static_cast(push_constant_ranges.size()); create_info.pPushConstantRanges = push_constant_ranges.data(); if (VkPipelineLayout object = VK_NULL_HANDLE; vk.CreatePipelineLayout(_orig, &create_info, nullptr, &object) == VK_SUCCESS) { - object_data data; - data.embedded_samplers = std::move(embedded_samplers); - data.set_layouts = std::move(set_layouts); - data.owns_set_layouts = true; - - register_object(object, std::move(data)); + register_object(object, std::move(layout_data)); *out_layout = { (uint64_t)object }; return true; @@ -2113,12 +2443,12 @@ bool reshade::vulkan::device_impl::create_pipeline_layout(uint32_t param_count, } exit_failure: - for (const VkSampler sampler : embedded_samplers) + for (const VkSampler sampler : layout_data.embedded_samplers) { vk.DestroySampler(_orig, sampler, nullptr); } - for (const VkDescriptorSetLayout set_layout : set_layouts) + for (const VkDescriptorSetLayout set_layout : layout_data.owned_set_layouts) { unregister_object(set_layout); @@ -2142,7 +2472,7 @@ void reshade::vulkan::device_impl::destroy_pipeline_layout(api::pipeline_layout if (layout_data->owns_set_layouts) { - for (const VkDescriptorSetLayout set_layout : layout_data->set_layouts) + for (const VkDescriptorSetLayout set_layout : layout_data->owned_set_layouts) { unregister_object(set_layout); @@ -2327,6 +2657,8 @@ void reshade::vulkan::device_impl::update_descriptor_tables(uint32_t count, cons break; case api::descriptor_type::constant_buffer: case api::descriptor_type::shader_storage_buffer: + case api::descriptor_type::constant_buffer_with_dynamic_offset: + case api::descriptor_type::shader_storage_buffer_with_dynamic_offset: write.pBufferInfo = static_cast(update.descriptors); break; #if VK_KHR_acceleration_structure @@ -2341,10 +2673,7 @@ void reshade::vulkan::device_impl::update_descriptor_tables(uint32_t count, cons break; #endif default: - if (write.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || write.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) - write.pBufferInfo = static_cast(update.descriptors); - else - assert(false); + assert(false); break; } } diff --git a/source/vulkan/vulkan_impl_device.hpp b/source/vulkan/vulkan_impl_device.hpp index d3d273bfc5..809f2691ae 100644 --- a/source/vulkan/vulkan_impl_device.hpp +++ b/source/vulkan/vulkan_impl_device.hpp @@ -73,9 +73,13 @@ namespace reshade::vulkan void update_texture_region(const api::subresource_data &data, api::resource dest, uint32_t dest_subresource, const api::subresource_box *dest_box) final; bool create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline) final; + bool create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline, const VkRayTracingPipelineCreateInfoKHR *orig_create_info); + bool create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline, const VkComputePipelineCreateInfo *orig_create_info); + bool create_pipeline(api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline *out_pipeline, const VkGraphicsPipelineCreateInfo *orig_create_info); void destroy_pipeline(api::pipeline pipeline) final; bool create_pipeline_layout(uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout *out_layout) final; + bool create_pipeline_layout(uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout *out_layout, const VkPipelineLayoutCreateInfo *orig_create_info); void destroy_pipeline_layout(api::pipeline_layout layout) final; bool allocate_descriptor_tables(uint32_t count, api::pipeline_layout layout, uint32_t layout_param, api::descriptor_table *out_tables) final; @@ -157,7 +161,7 @@ namespace reshade::vulkan const VkPhysicalDeviceFeatures _enabled_features; private: - bool create_shader_module(VkShaderStageFlagBits stage, const api::shader_desc &desc, VkPipelineShaderStageCreateInfo &stage_info, VkSpecializationInfo &spec_info, std::vector &spec_map); + bool create_descriptor_set_layout(const api::pipeline_layout_param ¶m, VkDescriptorSetLayout *out_set_layout, std::vector &embedded_samplers); VmaAllocator _alloc = nullptr; VkDescriptorPool _descriptor_pool = VK_NULL_HANDLE; diff --git a/source/vulkan/vulkan_impl_type_convert.cpp b/source/vulkan/vulkan_impl_type_convert.cpp index df5f7d1036..3004e2167e 100644 --- a/source/vulkan/vulkan_impl_type_convert.cpp +++ b/source/vulkan/vulkan_impl_type_convert.cpp @@ -3,9 +3,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "vulkan_hooks.hpp" #include "vulkan_impl_type_convert.hpp" -#include // std::copy_n, std::fill_n, std::find_if +#include +#include // std::copy_n, std::fill_n, std::find_if, std::max auto reshade::vulkan::convert_format(api::format format, VkComponentMapping *components) -> VkFormat { @@ -1646,6 +1646,9 @@ void reshade::vulkan::convert_dynamic_states(uint32_t count, const api::dynamic_ case api::dynamic_state::primitive_topology: internal_states.push_back(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY); break; + case api::dynamic_state::input_element_stride: + internal_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE); + break; case api::dynamic_state::depth_enable: internal_states.push_back(VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE); break; @@ -1730,6 +1733,8 @@ std::vector reshade::vulkan::convert_dynamic_states case VK_DYNAMIC_STATE_BLEND_CONSTANTS: states.push_back(api::dynamic_state::blend_constant); break; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS: + break; case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: states.push_back(api::dynamic_state::front_stencil_read_mask); states.push_back(api::dynamic_state::back_stencil_read_mask); @@ -1751,6 +1756,9 @@ std::vector reshade::vulkan::convert_dynamic_states case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY: states.push_back(api::dynamic_state::primitive_topology); break; + case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE: + states.push_back(api::dynamic_state::input_element_stride); + break; case VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE: states.push_back(api::dynamic_state::depth_enable); break; @@ -1760,6 +1768,8 @@ std::vector reshade::vulkan::convert_dynamic_states case VK_DYNAMIC_STATE_DEPTH_COMPARE_OP: states.push_back(api::dynamic_state::depth_func); break; + case VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE: + break; case VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE: states.push_back(api::dynamic_state::stencil_enable); break; @@ -1767,15 +1777,21 @@ std::vector reshade::vulkan::convert_dynamic_states states.push_back(api::dynamic_state::front_stencil_func); states.push_back(api::dynamic_state::back_stencil_func); break; + case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE: + break; case VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE: states.push_back(api::dynamic_state::depth_bias); states.push_back(api::dynamic_state::depth_bias_clamp); states.push_back(api::dynamic_state::depth_bias_slope_scaled); break; + case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE: + break; #if VK_EXT_extended_dynamic_state2 case VK_DYNAMIC_STATE_LOGIC_OP_EXT: states.push_back(api::dynamic_state::logic_op); break; + case VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT: + break; case VK_DYNAMIC_STATE_POLYGON_MODE_EXT: states.push_back(api::dynamic_state::fill_mode); break; @@ -2363,6 +2379,10 @@ auto reshade::vulkan::convert_descriptor_type(api::descriptor_type value) -> VkD return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; case api::descriptor_type::shader_storage_buffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + case api::descriptor_type::constant_buffer_with_dynamic_offset: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + case api::descriptor_type::shader_storage_buffer_with_dynamic_offset: + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; #if VK_KHR_acceleration_structure case api::descriptor_type::acceleration_structure: return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; @@ -2392,15 +2412,16 @@ auto reshade::vulkan::convert_descriptor_type(VkDescriptorType value) -> api::de return api::descriptor_type::constant_buffer; case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: return api::descriptor_type::shader_storage_buffer; + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + return api::descriptor_type::constant_buffer_with_dynamic_offset; + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + return api::descriptor_type::shader_storage_buffer_with_dynamic_offset; #if VK_KHR_acceleration_structure case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: return api::descriptor_type::acceleration_structure; #endif default: assert(false); - [[fallthrough]]; - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: return static_cast(value); } } diff --git a/source/vulkan/vulkan_impl_type_convert.hpp b/source/vulkan/vulkan_impl_type_convert.hpp index 272dfad90e..056fd3f24b 100644 --- a/source/vulkan/vulkan_impl_type_convert.hpp +++ b/source/vulkan/vulkan_impl_type_convert.hpp @@ -16,6 +16,15 @@ using VmaAllocation = void *; using VmaPool = void *; #endif +template +inline const T *find_in_structure_chain(const void *structure_chain, VkStructureType type) +{ + const T *next = reinterpret_cast(structure_chain); + while (next != nullptr && next->sType != type) + next = reinterpret_cast(next->pNext); + return next; +} + namespace reshade::vulkan { static_assert(sizeof(VkBuffer) == sizeof(api::resource)); @@ -121,6 +130,7 @@ namespace reshade::vulkan std::vector embedded_samplers; std::vector set_layouts; + std::vector owned_set_layouts; bool owns_set_layouts; };